Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package haproxy for openSUSE:Factory checked 
in at 2021-04-06 17:29:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/haproxy (Old)
 and      /work/SRC/openSUSE:Factory/.haproxy.new.2401 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "haproxy"

Tue Apr  6 17:29:34 2021 rev:101 rq:882208 version:2.3.9+git1.afb63bc04

Changes:
--------
--- /work/SRC/openSUSE:Factory/haproxy/haproxy.changes  2021-03-19 
16:39:46.257839889 +0100
+++ /work/SRC/openSUSE:Factory/.haproxy.new.2401/haproxy.changes        
2021-04-06 17:30:52.555198029 +0200
@@ -1,0 +2,40 @@
+Tue Mar 30 17:35:22 UTC 2021 - [email protected]
+
+- Update to version 2.3.9+git1.afb63bc04:
+  * BUILD: backend: fix build breakage in idle conn locking fix
+  * [RELEASE] Released version 2.3.9
+  * BUG/MEDIUM: time: make sure to always initialize the global tick
+  * BUG/MINOR: stats: Apply proper styles in HTML status page.
+  * BUG/MINOR: payload: Wait for more data if buffer is empty in 
payload/payload_lv
+  * MEDIUM: backend: use a trylock to grab a connection on high FD counts as 
well
+  * BUG/MEDIUM: mux-h1: make h1_shutw_conn() idempotent
+
+-------------------------------------------------------------------
+Thu Mar 25 15:51:22 UTC 2021 - [email protected]
+
+- Update to version 2.3.8+git0.e572195c7:
+  * [RELEASE] Released version 2.3.8
+  * BUG/MINOR: http_fetch: make hdr_ip() reject trailing characters
+  * MINOR: tools: make url2ipv4 return the exact number of bytes parsed
+  * BUG/MEDIUM: thread: Fix a deadlock if an isolated thread is marked as 
harmless
+  * BUG/MEDIUM: fd: Take the fd_mig_lock when closing if no DWCAS is available.
+  * CLEANUP: fd: remove unused fd_set_running_excl()
+  * BUG/MEDIUM: fd: do not wait on FD removal in fd_delete()
+  * MINOR: fd: remove the unneeded running bit from fd_insert()
+  * MINOR: fd: make fd_clr_running() return the remaining running mask
+  * BUG/MEDIUM: lua: Always init the lua stack before referencing the context
+  * BUG/MEDIUM: debug/lua: Use internal hlua function to dump the lua traceback
+  * MINOR: lua: Slightly improve function dumping the lua traceback
+  * BUILD: ssl: guard ecdh functions with SSL_CTX_set_tmp_ecdh macro
+  * BUG/MINOR: ssl: Prevent disk access when using "add ssl crt-list"
+  * BUG/MEDIUM: debug/lua: Don't dump the lua stack if not dumpable
+  * MEDIUM: lua: Use a per-thread counter to track some non-reentrant parts of 
lua
+  * MINOR/BUG: mworker/cli: do not use the unix_bind prefix for the master CLI 
socket
+  * BUG/MINOR: protocol: add missing support of dgram unix socket.
+  * BUG/MEDIUM: freq_ctr/threads: use the global_now_ms variable
+  * MINOR: time: also provide a global, monotonic global_now_ms timer
+  * BUG/MEDIUM: mux-fcgi: Fix locking of idle_conns lock in the FCGI I/O 
callback
+  * BUG/MINOR: freq_ctr/threads: make use of the last updated global time
+  * MINOR: time: export the global_now variable
+
+-------------------------------------------------------------------

Old:
----
  haproxy-2.3.7+git0.2d39ce334.tar.gz

New:
----
  haproxy-2.3.9+git1.afb63bc04.tar.gz

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

Other differences:
------------------
++++++ haproxy.spec ++++++
--- /var/tmp/diff_new_pack.1wa2Eb/_old  2021-04-06 17:30:53.247198812 +0200
+++ /var/tmp/diff_new_pack.1wa2Eb/_new  2021-04-06 17:30:53.251198816 +0200
@@ -53,7 +53,7 @@
 %endif
 
 Name:           haproxy
-Version:        2.3.7+git0.2d39ce334
+Version:        2.3.9+git1.afb63bc04
 Release:        0
 #
 #

++++++ _service ++++++
--- /var/tmp/diff_new_pack.1wa2Eb/_old  2021-04-06 17:30:53.291198862 +0200
+++ /var/tmp/diff_new_pack.1wa2Eb/_new  2021-04-06 17:30:53.295198866 +0200
@@ -6,7 +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">v2.3.7</param>
+    <param name="revision">v2.3.9</param>
     <param name="changesgenerate">enable</param>
   </service>
 

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.1wa2Eb/_old  2021-04-06 17:30:53.319198893 +0200
+++ /var/tmp/diff_new_pack.1wa2Eb/_new  2021-04-06 17:30:53.319198893 +0200
@@ -7,4 +7,4 @@
                 <param 
name="url">http://git.haproxy.org/git/haproxy-2.2.git</param>
               <param 
name="changesrevision">34b2b106689c8a017eb5726193b199ea96f2c9f7</param></service><service
 name="tar_scm">
                 <param 
name="url">http://git.haproxy.org/git/haproxy-2.3.git</param>
-              <param 
name="changesrevision">2d39ce334654fae7760f8708d50477150e7af87c</param></service></servicedata>
\ No newline at end of file
+              <param 
name="changesrevision">afb63bc040ab53db7520eaef49b79970d2b636d9</param></service></servicedata>
\ No newline at end of file

++++++ haproxy-2.3.7+git0.2d39ce334.tar.gz -> 
haproxy-2.3.9+git1.afb63bc04.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/CHANGELOG 
new/haproxy-2.3.9+git1.afb63bc04/CHANGELOG
--- old/haproxy-2.3.7+git0.2d39ce334/CHANGELOG  2021-03-16 15:49:34.000000000 
+0100
+++ new/haproxy-2.3.9+git1.afb63bc04/CHANGELOG  2021-03-30 18:51:07.000000000 
+0200
@@ -1,6 +1,37 @@
 ChangeLog :
 ===========
 
+2021/03/30 : 2.3.9
+    - BUG/MEDIUM: mux-h1: make h1_shutw_conn() idempotent
+    - MEDIUM: backend: use a trylock to grab a connection on high FD counts as 
well
+    - BUG/MINOR: payload: Wait for more data if buffer is empty in 
payload/payload_lv
+    - BUG/MINOR: stats: Apply proper styles in HTML status page.
+    - BUG/MEDIUM: time: make sure to always initialize the global tick
+
+2021/03/25 : 2.3.8
+    - MINOR: time: export the global_now variable
+    - BUG/MINOR: freq_ctr/threads: make use of the last updated global time
+    - BUG/MEDIUM: mux-fcgi: Fix locking of idle_conns lock in the FCGI I/O 
callback
+    - MINOR: time: also provide a global, monotonic global_now_ms timer
+    - BUG/MEDIUM: freq_ctr/threads: use the global_now_ms variable
+    - BUG/MINOR: protocol: add missing support of dgram unix socket.
+    - MINOR/BUG: mworker/cli: do not use the unix_bind prefix for the master 
CLI socket
+    - MEDIUM: lua: Use a per-thread counter to track some non-reentrant parts 
of lua
+    - BUG/MEDIUM: debug/lua: Don't dump the lua stack if not dumpable
+    - BUG/MINOR: ssl: Prevent disk access when using "add ssl crt-list"
+    - BUILD: ssl: guard ecdh functions with SSL_CTX_set_tmp_ecdh macro
+    - MINOR: lua: Slightly improve function dumping the lua traceback
+    - BUG/MEDIUM: debug/lua: Use internal hlua function to dump the lua 
traceback
+    - BUG/MEDIUM: lua: Always init the lua stack before referencing the context
+    - MINOR: fd: make fd_clr_running() return the remaining running mask
+    - MINOR: fd: remove the unneeded running bit from fd_insert()
+    - BUG/MEDIUM: fd: do not wait on FD removal in fd_delete()
+    - CLEANUP: fd: remove unused fd_set_running_excl()
+    - BUG/MEDIUM: fd: Take the fd_mig_lock when closing if no DWCAS is 
available.
+    - BUG/MEDIUM: thread: Fix a deadlock if an isolated thread is marked as 
harmless
+    - MINOR: tools: make url2ipv4 return the exact number of bytes parsed
+    - BUG/MINOR: http_fetch: make hdr_ip() reject trailing characters
+
 2021/03/16 : 2.3.7
     - BUG/MINOR: backend: fix condition for reuse on mode HTTP
     - BUG/MINOR: hlua: Don't strip last non-LWS char in 
hlua_pushstrippedstring()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/Makefile 
new/haproxy-2.3.9+git1.afb63bc04/Makefile
--- old/haproxy-2.3.7+git0.2d39ce334/Makefile   2021-03-16 15:49:34.000000000 
+0100
+++ new/haproxy-2.3.9+git1.afb63bc04/Makefile   2021-03-30 18:51:07.000000000 
+0200
@@ -857,7 +857,7 @@
         src/ebimtree.o src/uri_auth.o src/freq_ctr.o src/ebsttree.o            
\
         src/ebistree.o src/auth.o src/wdt.o src/http_acl.o                     
\
         src/hpack-enc.o src/hpack-huff.o src/ebtree.o src/base64.o             
\
-        src/hash.o src/dgram.o src/version.o
+        src/hash.o src/dgram.o src/version.o src/proto_uxdg.o
 
 ifneq ($(TRACE),)
 OBJS += src/calltrace.o
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/VERDATE 
new/haproxy-2.3.9+git1.afb63bc04/VERDATE
--- old/haproxy-2.3.7+git0.2d39ce334/VERDATE    2021-03-16 15:49:34.000000000 
+0100
+++ new/haproxy-2.3.9+git1.afb63bc04/VERDATE    2021-03-30 18:51:07.000000000 
+0200
@@ -1,2 +1,2 @@
 $Format:%ci$
-2021/03/16
+2021/03/30
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/VERSION 
new/haproxy-2.3.9+git1.afb63bc04/VERSION
--- old/haproxy-2.3.7+git0.2d39ce334/VERSION    2021-03-16 15:49:34.000000000 
+0100
+++ new/haproxy-2.3.9+git1.afb63bc04/VERSION    2021-03-30 18:51:07.000000000 
+0200
@@ -1 +1 @@
-2.3.7
+2.3.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/doc/configuration.txt 
new/haproxy-2.3.9+git1.afb63bc04/doc/configuration.txt
--- old/haproxy-2.3.7+git0.2d39ce334/doc/configuration.txt      2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/doc/configuration.txt      2021-03-30 
18:51:07.000000000 +0200
@@ -4,7 +4,7 @@
                          ----------------------
                               version 2.3
                              willy tarreau
-                              2021/03/16
+                              2021/03/30
 
 
 This document covers the configuration language as implemented in the version
@@ -18330,7 +18330,11 @@
   This extracts the last occurrence of header <name> in an HTTP request,
   converts it to an IPv4 or IPv6 address and returns this address. When used
   with ACLs, all occurrences are checked, and if <name> is omitted, every value
-  of every header is checked.
+  of every header is checked. The parser strictly adheres to the format
+  described in RFC7239, with the extension that IPv4 addresses may optionally
+  be followed by a colon (':') and a valid decimal port number (0 to 65535),
+  which will be silently dropped. All other forms will not match and will
+  cause the address to be ignored.
 
   The <occ> parameter is processed as with req.hdr().
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/fd.h 
new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/fd.h
--- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/fd.h       2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/fd.h       2021-03-30 
18:51:07.000000000 +0200
@@ -59,6 +59,7 @@
  * The file descriptor is also closed.
  */
 void fd_delete(int fd);
+void _fd_delete_orphan(int fd);
 
 /*
  * Take over a FD belonging to another thread.
@@ -340,17 +341,12 @@
 #endif
 }
 
-static inline void fd_set_running_excl(int fd)
-{
-       unsigned long old_mask = 0;
-       while (!_HA_ATOMIC_CAS(&fdtab[fd].running_mask, &old_mask, tid_bit))
-               old_mask = 0;
-}
-
-
-static inline void fd_clr_running(int fd)
+/* remove tid_bit from the fd's running mask and returns the bits that remain
+ * after the atomic operation.
+ */
+static inline long fd_clr_running(int fd)
 {
-       _HA_ATOMIC_AND(&fdtab[fd].running_mask, ~tid_bit);
+       return _HA_ATOMIC_AND(&fdtab[fd].running_mask, ~tid_bit);
 }
 
 /* Update events seen for FD <fd> and its state if needed. This should be
@@ -411,7 +407,9 @@
                if (fd_set_running(fd) == -1)
                        return;
                fdtab[fd].iocb(fd);
-               fd_clr_running(fd);
+               if ((fdtab[fd].running_mask & tid_bit) &&
+                   fd_clr_running(fd) == 0 && !fdtab[fd].thread_mask)
+                       _fd_delete_orphan(fd);
        }
 
        /* we had to stop this FD and it still must be stopped after the I/O
@@ -430,11 +428,8 @@
 /* Prepares <fd> for being polled */
 static inline void fd_insert(int fd, void *owner, void (*iocb)(int fd), 
unsigned long thread_mask)
 {
-       int locked = fdtab[fd].running_mask != tid_bit;
        extern void conn_fd_handler(int);
 
-       if (locked)
-               fd_set_running_excl(fd);
        fdtab[fd].owner = owner;
        fdtab[fd].iocb = iocb;
        fdtab[fd].ev = 0;
@@ -454,8 +449,7 @@
        /* note: do not reset polled_mask here as it indicates which poller
         * still knows this FD from a possible previous round.
         */
-       if (locked)
-               fd_clr_running(fd);
+
        /* the two directions are ready until proven otherwise */
        fd_may_both(fd);
        _HA_ATOMIC_ADD(&ha_used_fds, 1);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/freq_ctr.h 
new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/freq_ctr.h
--- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/freq_ctr.h 2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/freq_ctr.h 2021-03-30 
18:51:07.000000000 +0200
@@ -36,6 +36,7 @@
 {
        int elapsed;
        unsigned int curr_sec;
+       uint32_t now_tmp;
 
 
        /* we manipulate curr_ctr using atomic ops out of the lock, since
@@ -47,16 +48,17 @@
         * same uncertainty as well.
         */
        curr_sec = ctr->curr_sec;
-       if (curr_sec == (now.tv_sec & 0x7fffffff))
-               return _HA_ATOMIC_ADD(&ctr->curr_ctr, inc);
-
        do {
+               now_tmp = global_now >> 32;
+               if (curr_sec == (now_tmp & 0x7fffffff))
+                       return _HA_ATOMIC_ADD(&ctr->curr_ctr, inc);
+
                /* remove the bit, used for the lock */
                curr_sec &= 0x7fffffff;
        } while (!_HA_ATOMIC_CAS(&ctr->curr_sec, &curr_sec, curr_sec | 
0x80000000));
        __ha_barrier_atomic_store();
 
-       elapsed = (now.tv_sec & 0x7fffffff)- curr_sec;
+       elapsed = (now_tmp & 0x7fffffff) - curr_sec;
        if (unlikely(elapsed > 0)) {
                ctr->prev_ctr = ctr->curr_ctr;
                _HA_ATOMIC_SUB(&ctr->curr_ctr, ctr->prev_ctr);
@@ -64,7 +66,7 @@
                        /* we missed more than one second */
                        ctr->prev_ctr = 0;
                }
-               curr_sec = now.tv_sec;
+               curr_sec = now_tmp;
        }
 
        /* release the lock and update the time in case of rotate. */
@@ -82,25 +84,27 @@
                                                  unsigned int period, unsigned 
int inc)
 {
        unsigned int curr_tick;
+       uint32_t now_ms_tmp;
 
        curr_tick = ctr->curr_tick;
-       if (now_ms - curr_tick < period)
-               return _HA_ATOMIC_ADD(&ctr->curr_ctr, inc);
-
        do {
+               now_ms_tmp = global_now_ms;
+               if (now_ms_tmp - curr_tick < period)
+                       return _HA_ATOMIC_ADD(&ctr->curr_ctr, inc);
+
                /* remove the bit, used for the lock */
                curr_tick &= ~1;
        } while (!_HA_ATOMIC_CAS(&ctr->curr_tick, &curr_tick, curr_tick | 0x1));
        __ha_barrier_atomic_store();
 
-       if (now_ms - curr_tick >= period) {
+       if (now_ms_tmp - curr_tick >= period) {
                ctr->prev_ctr = ctr->curr_ctr;
                _HA_ATOMIC_SUB(&ctr->curr_ctr, ctr->prev_ctr);
                curr_tick += period;
-               if (likely(now_ms - curr_tick >= period)) {
+               if (likely(now_ms_tmp - curr_tick >= period)) {
                        /* we missed at least two periods */
                        ctr->prev_ctr = 0;
-                       curr_tick = now_ms;
+                       curr_tick = now_ms_tmp;
                }
                curr_tick &= ~1;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/hlua.h 
new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/hlua.h
--- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/hlua.h     2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/hlua.h     2021-03-30 
18:51:07.000000000 +0200
@@ -43,6 +43,7 @@
 #define HLUA_INIT(__hlua) do { (__hlua)->T = 0; } while(0)
 
 /* Lua HAProxy integration functions. */
+const char *hlua_traceback(lua_State *L, const char* sep);
 void hlua_ctx_destroy(struct hlua *lua);
 void hlua_init();
 int hlua_post_init();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/listener-t.h 
new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/listener-t.h
--- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/listener-t.h       
2021-03-16 15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/listener-t.h       
2021-03-30 18:51:07.000000000 +0200
@@ -239,7 +239,7 @@
 };
 struct ssl_bind_kw {
        const char *kw;
-       int (*parse)(char **args, int cur_arg, struct proxy *px, struct 
ssl_bind_conf *conf, char **err);
+       int (*parse)(char **args, int cur_arg, struct proxy *px, struct 
ssl_bind_conf *conf, int from_cli, char **err);
        int skip; /* nb of args to skip */
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/ssl_crtlist.h 
new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/ssl_crtlist.h
--- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/ssl_crtlist.h      
2021-03-16 15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/ssl_crtlist.h      
2021-03-30 18:51:07.000000000 +0200
@@ -38,7 +38,7 @@
 struct crtlist *crtlist_new(const char *filename, int unique);
 
 /* file loading */
-int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry 
*entry, const char *file, int linenum, char **err);
+int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry 
*entry, const char *file, int linenum, int from_cli, char **err);
 int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy 
*curproxy, struct crtlist **crtlist, char **err);
 int crtlist_load_cert_dir(char *path, struct bind_conf *bind_conf, struct 
crtlist **crtlist, char **err);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/ssl_sock.h 
new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/ssl_sock.h
--- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/ssl_sock.h 2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/ssl_sock.h 2021-03-30 
18:51:07.000000000 +0200
@@ -104,7 +104,7 @@
 void ssl_free_global_issuers(void);
 int ssl_sock_load_cert_list_file(char *file, int dir, struct bind_conf 
*bind_conf, struct proxy *curproxy, char **err);
 int ssl_init_single_engine(const char *engine_id, const char *def_algorithms);
-int ssl_store_load_locations_file(char *path);
+int ssl_store_load_locations_file(char *path, int create_if_none);
 
 /* ssl shctx macro */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/time.h 
new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/time.h
--- old/haproxy-2.3.7+git0.2d39ce334/include/haproxy/time.h     2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/include/haproxy/time.h     2021-03-30 
18:51:07.000000000 +0200
@@ -60,6 +60,8 @@
 extern struct timeval start_date;       /* the process's start date */
 extern THREAD_LOCAL struct timeval before_poll;      /* system date before 
calling poll() */
 extern THREAD_LOCAL struct timeval after_poll;       /* system date after 
leaving poll() */
+extern volatile unsigned long long global_now;
+extern volatile unsigned int global_now_ms;
 
 
 /**** exported functions *************************************************/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/haproxy-2.3.7+git0.2d39ce334/reg-tests/ssl/add_ssl_crt-list.vtc 
new/haproxy-2.3.9+git1.afb63bc04/reg-tests/ssl/add_ssl_crt-list.vtc
--- old/haproxy-2.3.7+git0.2d39ce334/reg-tests/ssl/add_ssl_crt-list.vtc 
2021-03-16 15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/reg-tests/ssl/add_ssl_crt-list.vtc 
2021-03-30 18:51:07.000000000 +0200
@@ -93,3 +93,22 @@
     rxresp
     expect resp.status == 200
 } -run
+
+
+# Try to add a new line that mentions an "unknown" CA file (not loaded yet).
+# It should fail since no disk access are allowed during runtime.
+shell {
+    printf "add ssl crt-list ${testdir}/localhost.crt-list/ 
<<\n${testdir}/ecdsa.pem [ca-file ${testdir}/ca-auth.crt] localhost\n\n" | 
socat "${tmpdir}/h1/stats" - | grep "unable to load ${testdir}/ca-auth.crt"
+}
+shell {
+    printf "add ssl crt-list ${testdir}/localhost.crt-list/ 
<<\n${testdir}/ecdsa.pem [ca-verify-file ${testdir}/ca-auth.crt] localhost\n\n" 
| socat "${tmpdir}/h1/stats" - | grep "unable to load ${testdir}/ca-auth.crt"
+}
+shell {
+    printf "add ssl crt-list ${testdir}/localhost.crt-list/ 
<<\n${testdir}/ecdsa.pem [crl-file ${testdir}/ca-auth.crt] localhost\n\n" | 
socat "${tmpdir}/h1/stats" - | grep "unable to load ${testdir}/ca-auth.crt"
+}
+
+# Check that the new line was not added to the crt-list.
+haproxy h1 -cli {
+    send "show ssl crt-list ${testdir}/localhost.crt-list//"
+    expect !~ ".*ca-file ${testdir}/ca-auth.crt"
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/backend.c 
new/haproxy-2.3.9+git1.afb63bc04/src/backend.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/backend.c      2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/backend.c      2021-03-30 
18:51:07.000000000 +0200
@@ -1358,7 +1358,9 @@
                                // see it possibly larger.
                                ALREADY_CHECKED(i);
 
-                               HA_SPIN_LOCK(OTHER_LOCK, 
&idle_conns[i].takeover_lock);
+                               if (HA_SPIN_TRYLOCK(OTHER_LOCK, 
&idle_conns[i].takeover_lock) != 0)
+                                       continue;
+
                                tokill_conn = MT_LIST_POP(&srv->idle_conns[i],
                                    struct connection *, list);
                                if (!tokill_conn)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/cfgparse-ssl.c 
new/haproxy-2.3.9+git1.afb63bc04/src/cfgparse-ssl.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/cfgparse-ssl.c 2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/cfgparse-ssl.c 2021-03-30 
18:51:07.000000000 +0200
@@ -530,7 +530,7 @@
 /***************************** Bind keyword Parsing 
********************************************/
 
 /* for ca-file and ca-verify-file */
-static int ssl_bind_parse_ca_file_common(char **args, int cur_arg, char 
**ca_file_p, char **err)
+static int ssl_bind_parse_ca_file_common(char **args, int cur_arg, char 
**ca_file_p, int from_cli, char **err)
 {
        if (!*args[cur_arg + 1]) {
                memprintf(err, "'%s' : missing CAfile path", args[cur_arg]);
@@ -542,7 +542,7 @@
        else
                memprintf(ca_file_p, "%s", args[cur_arg + 1]);
 
-       if (!ssl_store_load_locations_file(*ca_file_p)) {
+       if (!ssl_store_load_locations_file(*ca_file_p, !from_cli)) {
                memprintf(err, "'%s' : unable to load %s", args[cur_arg], 
*ca_file_p);
                return ERR_ALERT | ERR_FATAL;
        }
@@ -550,23 +550,23 @@
 }
 
 /* parse the "ca-file" bind keyword */
-static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, int from_cli, char **err)
 {
-       return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_file, 
err);
+       return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_file, 
from_cli, err);
 }
 static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, 
struct bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_ca_file(args, cur_arg, px, &conf->ssl_conf, err);
+       return ssl_bind_parse_ca_file(args, cur_arg, px, &conf->ssl_conf, 0, 
err);
 }
 
 /* parse the "ca-verify-file" bind keyword */
-static int ssl_bind_parse_ca_verify_file(char **args, int cur_arg, struct 
proxy *px, struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_ca_verify_file(char **args, int cur_arg, struct 
proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
 {
-       return ssl_bind_parse_ca_file_common(args, cur_arg, 
&conf->ca_verify_file, err);
+       return ssl_bind_parse_ca_file_common(args, cur_arg, 
&conf->ca_verify_file, from_cli, err);
 }
 static int bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy 
*px, struct bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_ca_verify_file(args, cur_arg, px, 
&conf->ssl_conf, err);
+       return ssl_bind_parse_ca_verify_file(args, cur_arg, px, 
&conf->ssl_conf, 0, err);
 }
 
 /* parse the "ca-sign-file" bind keyword */
@@ -597,7 +597,7 @@
 }
 
 /* parse the "ciphers" bind keyword */
-static int ssl_bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, int from_cli, char **err)
 {
        if (!*args[cur_arg + 1]) {
                memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
@@ -610,12 +610,12 @@
 }
 static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, 
struct bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, err);
+       return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, 0, 
err);
 }
 
 #if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
 /* parse the "ciphersuites" bind keyword */
-static int ssl_bind_parse_ciphersuites(char **args, int cur_arg, struct proxy 
*px, struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_ciphersuites(char **args, int cur_arg, struct proxy 
*px, struct ssl_bind_conf *conf, int from_cli, char **err)
 {
        if (!*args[cur_arg + 1]) {
                memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
@@ -628,7 +628,7 @@
 }
 static int bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, 
struct bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_ciphersuites(args, cur_arg, px, &conf->ssl_conf, 
err);
+       return ssl_bind_parse_ciphersuites(args, cur_arg, px, &conf->ssl_conf, 
0, err);
 }
 #endif
 
@@ -672,7 +672,7 @@
 }
 
 /* parse the "crl-file" bind keyword */
-static int ssl_bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, int from_cli, char **err)
 {
 #ifndef X509_V_FLAG_CRL_CHECK
        memprintf(err, "'%s' : library does not support CRL verify", 
args[cur_arg]);
@@ -688,7 +688,7 @@
        else
                memprintf(&conf->crl_file, "%s", args[cur_arg + 1]);
 
-       if (!ssl_store_load_locations_file(conf->crl_file)) {
+       if (!ssl_store_load_locations_file(conf->crl_file, !from_cli)) {
                memprintf(err, "'%s' : unable to load %s", args[cur_arg], 
conf->crl_file);
                return ERR_ALERT | ERR_FATAL;
        }
@@ -697,11 +697,11 @@
 }
 static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, 
struct bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_crl_file(args, cur_arg, px, &conf->ssl_conf, err);
+       return ssl_bind_parse_crl_file(args, cur_arg, px, &conf->ssl_conf, 0, 
err);
 }
 
 /* parse the "curves" bind keyword keyword */
-static int ssl_bind_parse_curves(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_curves(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, int from_cli, char **err)
 {
 #if defined(SSL_CTX_set1_curves_list)
        if (!*args[cur_arg + 1]) {
@@ -717,13 +717,13 @@
 }
 static int bind_parse_curves(char **args, int cur_arg, struct proxy *px, 
struct bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_curves(args, cur_arg, px, &conf->ssl_conf, err);
+       return ssl_bind_parse_curves(args, cur_arg, px, &conf->ssl_conf, 0, 
err);
 }
 
 /* parse the "ecdhe" bind keyword keyword */
-static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, int from_cli, char **err)
 {
-#if HA_OPENSSL_VERSION_NUMBER < 0x0090800fL
+#if !defined(SSL_CTX_set_tmp_ecdh)
        memprintf(err, "'%s' : library does not support elliptic curve 
Diffie-Hellman (too old)", args[cur_arg]);
        return ERR_ALERT | ERR_FATAL;
 #elif defined(OPENSSL_NO_ECDH)
@@ -742,7 +742,7 @@
 }
 static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct 
bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_ecdhe(args, cur_arg, px, &conf->ssl_conf, err);
+       return ssl_bind_parse_ecdhe(args, cur_arg, px, &conf->ssl_conf, 0, err);
 }
 
 /* parse the "crt-ignore-err" and "ca-ignore-err" bind keywords */
@@ -851,7 +851,7 @@
        return 0;
 }
 
-static int ssl_bind_parse_tls_method_minmax(char **args, int cur_arg, struct 
proxy *px, struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_tls_method_minmax(char **args, int cur_arg, struct 
proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
 {
        int ret;
 
@@ -885,7 +885,7 @@
 }
 
 /* parse the "allow-0rtt" bind keyword */
-static int ssl_bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy 
*px, struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_allow_0rtt(char **args, int cur_arg, struct proxy 
*px, struct ssl_bind_conf *conf, int from_cli, char **err)
 {
        conf->early_data = 1;
        return 0;
@@ -898,7 +898,7 @@
 }
 
 /* parse the "npn" bind keyword */
-static int ssl_bind_parse_npn(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_npn(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, int from_cli, char **err)
 {
 #if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
        char *p1, *p2;
@@ -949,7 +949,7 @@
 
 static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct 
bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_npn(args, cur_arg, px, &conf->ssl_conf, err);
+       return ssl_bind_parse_npn(args, cur_arg, px, &conf->ssl_conf, 0, err);
 }
 
 
@@ -1015,7 +1015,7 @@
 }
 
 /* parse the "alpn" bind keyword */
-static int ssl_bind_parse_alpn(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_alpn(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, int from_cli, char **err)
 {
 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
        int ret;
@@ -1034,7 +1034,7 @@
 
 static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct 
bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, err);
+       return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, 0, err);
 }
 
 /* parse the "ssl" bind keyword */
@@ -1201,7 +1201,7 @@
 }
 
 /* parse the "verify" bind keyword */
-static int ssl_bind_parse_verify(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_verify(char **args, int cur_arg, struct proxy *px, 
struct ssl_bind_conf *conf, int from_cli, char **err)
 {
        if (!*args[cur_arg + 1]) {
                memprintf(err, "'%s' : missing verify method", args[cur_arg]);
@@ -1224,18 +1224,18 @@
 }
 static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, 
struct bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_verify(args, cur_arg, px, &conf->ssl_conf, err);
+       return ssl_bind_parse_verify(args, cur_arg, px, &conf->ssl_conf, 0, 
err);
 }
 
 /* parse the "no-ca-names" bind keyword */
-static int ssl_bind_parse_no_ca_names(char **args, int cur_arg, struct proxy 
*px, struct ssl_bind_conf *conf, char **err)
+static int ssl_bind_parse_no_ca_names(char **args, int cur_arg, struct proxy 
*px, struct ssl_bind_conf *conf, int from_cli, char **err)
 {
        conf->no_ca_names = 1;
        return 0;
 }
 static int bind_parse_no_ca_names(char **args, int cur_arg, struct proxy *px, 
struct bind_conf *conf, char **err)
 {
-       return ssl_bind_parse_no_ca_names(args, cur_arg, px, &conf->ssl_conf, 
err);
+       return ssl_bind_parse_no_ca_names(args, cur_arg, px, &conf->ssl_conf, 
0, err);
 }
 
 /***************************** "server" keywords Parsing 
********************************************/
@@ -1333,7 +1333,7 @@
        else
                memprintf(&newsrv->ssl_ctx.ca_file, "%s", args[*cur_arg + 1]);
 
-       if (!ssl_store_load_locations_file(newsrv->ssl_ctx.ca_file)) {
+       if (!ssl_store_load_locations_file(newsrv->ssl_ctx.ca_file, 1)) {
                memprintf(err, "'%s' : unable to load %s", args[*cur_arg], 
newsrv->ssl_ctx.ca_file);
                return ERR_ALERT | ERR_FATAL;
        }
@@ -1422,7 +1422,7 @@
        else
                memprintf(&newsrv->ssl_ctx.crl_file, "%s", args[*cur_arg + 1]);
 
-       if (!ssl_store_load_locations_file(newsrv->ssl_ctx.crl_file)) {
+       if (!ssl_store_load_locations_file(newsrv->ssl_ctx.crl_file, 1)) {
                memprintf(err, "'%s' : unable to load %s", args[*cur_arg], 
newsrv->ssl_ctx.crl_file);
                return ERR_ALERT | ERR_FATAL;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/cfgparse.c 
new/haproxy-2.3.9+git1.afb63bc04/src/cfgparse.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/cfgparse.c     2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/cfgparse.c     2021-03-30 
18:51:07.000000000 +0200
@@ -87,6 +87,8 @@
 
 struct list postparsers = LIST_HEAD_INIT(postparsers);
 
+extern struct proxy *mworker_proxy;
+
 char *cursection = NULL;
 struct proxy defproxy = { };           /* fake proxy used to assign default 
values on all instances */
 int cfg_maxpconn = 0;                   /* # of simultaneous connections per 
proxy (-N) */
@@ -128,7 +130,7 @@
                }
 
                ss2 = str2sa_range(str, NULL, &port, &end, &fd, &proto, err,
-                                  curproxy == global.stats_fe ? NULL : 
global.unix_bind.prefix,
+                                  (curproxy == global.stats_fe || curproxy == 
mworker_proxy) ? NULL : global.unix_bind.prefix,
                                   NULL, PA_O_RESOLVE | PA_O_PORT_OK | 
PA_O_PORT_MAND | PA_O_PORT_RANGE |
                                          PA_O_SOCKET_FD | PA_O_STREAM | 
PA_O_XPRT);
                if (!ss2)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/cli.c 
new/haproxy-2.3.9+git1.afb63bc04/src/cli.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/cli.c  2021-03-16 15:49:34.000000000 
+0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/cli.c  2021-03-30 18:51:07.000000000 
+0200
@@ -89,7 +89,7 @@
 
 extern const char *stat_status_codes[];
 
-static struct proxy *mworker_proxy; /* CLI proxy of the master */
+struct proxy *mworker_proxy; /* CLI proxy of the master */
 
 static char *cli_gen_usage_msg(struct appctx *appctx)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/debug.c 
new/haproxy-2.3.9+git1.afb63bc04/src/debug.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/debug.c        2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/debug.c        2021-03-30 
18:51:07.000000000 +0200
@@ -223,9 +223,9 @@
        }
 
        if (hlua && hlua->T) {
-               luaL_traceback(hlua->T, hlua->T, NULL, 0);
-               if (!append_prefixed_str(buf, lua_tostring(hlua->T, -1), pfx, 
'\n', 1))
-                       b_putchr(buf, '\n');
+               chunk_appendf(buf, "stack traceback:\n    ");
+               append_prefixed_str(buf, hlua_traceback(hlua->T, "\n    "), 
pfx, '\n', 0);
+               b_putchr(buf, '\n');
        }
        else
                b_putchr(buf, '\n');
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/fd.c 
new/haproxy-2.3.9+git1.afb63bc04/src/fd.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/fd.c   2021-03-16 15:49:34.000000000 
+0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/fd.c   2021-03-30 18:51:07.000000000 
+0200
@@ -294,23 +294,14 @@
 #undef _GET_NEXT
 #undef _GET_PREV
 
-/* Deletes an FD from the fdsets.
- * The file descriptor is also closed.
+/* deletes the FD once nobody uses it anymore, as detected by the caller by its
+ * thread_mask being zero and its running mask turning to zero. There is no
+ * protection against concurrent accesses, it's up to the caller to make sure
+ * only the last thread will call it. This is only for internal use, please use
+ * fd_delete() instead.
  */
-void fd_delete(int fd)
+void _fd_delete_orphan(int fd)
 {
-       int locked = fdtab[fd].running_mask != tid_bit;
-
-       /* We're just trying to protect against a concurrent fd_insert()
-        * here, not against fd_takeover(), because either we're called
-        * directly from the iocb(), and we're already locked, or we're
-        * called from the mux tasklet, but then the mux is responsible for
-        * making sure the tasklet does nothing, and the connection is never
-        * destroyed.
-        */
-       if (locked)
-               fd_set_running_excl(fd);
-
        if (fdtab[fd].linger_risk) {
                /* this is generally set when connecting to servers */
                DISGUISE(setsockopt(fd, SOL_SOCKET, SO_LINGER,
@@ -328,18 +319,51 @@
        port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
        fdinfo[fd].port_range = NULL;
        fdtab[fd].owner = NULL;
-       fdtab[fd].thread_mask = 0;
        fdtab[fd].exported = 0;
+       /* perform the close() call last as it's what unlocks the instant reuse
+        * of this FD by any other thread.
+        */
        close(fd);
        _HA_ATOMIC_SUB(&ha_used_fds, 1);
-       if (locked)
-               fd_clr_running(fd);
 }
 
 #ifndef HA_HAVE_CAS_DW
 __decl_thread(__decl_rwlock(fd_mig_lock));
 #endif
 
+/* Deletes an FD from the fdsets. The file descriptor is also closed, possibly
+ * asynchronously. Only the owning thread may do this.
+ */
+void fd_delete(int fd)
+{
+       /* we must postpone removal of an FD that may currently be in use
+        * by another thread. This can happend in the following two situations:
+        *   - after a takeover, the owning thread closes the connection but
+        *     the previous one just woke up from the poller and entered
+        *     the FD handler iocb. That thread holds an entry in running_mask
+        *     and requires removal protection.
+        *   - multiple threads are accepting connections on a listener, and
+        *     one of them (or even an separate one) decides to unbind the
+        *     listener under the listener's lock while other ones still hold
+        *     the running bit.
+        * In both situations the FD is marked as unused (thread_mask = 0) and
+        * will not take new bits in its running_mask so we have the guarantee
+        * that the last thread eliminating running_mask is the one allowed to
+        * safely delete the FD. Most of the time it will be the current thread.
+        */
+
+       HA_ATOMIC_OR(&fdtab[fd].running_mask, tid_bit);
+#ifndef HA_HAVE_CAS_DW
+       HA_RWLOCK_WRLOCK(OTHER_LOCK, &fd_mig_lock);
+#endif
+       HA_ATOMIC_STORE(&fdtab[fd].thread_mask, 0);
+#ifndef HA_HAVE_CAS_DW
+       HA_RWLOCK_WRUNLOCK(OTHER_LOCK, &fd_mig_lock);
+#endif
+       if (fd_clr_running(fd) == 0)
+               _fd_delete_orphan(fd);
+}
+
 /*
  * Take over a FD belonging to another thread.
  * unexpected_conn is the expected owner of the fd.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/freq_ctr.c 
new/haproxy-2.3.9+git1.afb63bc04/src/freq_ctr.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/freq_ctr.c     2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/freq_ctr.c     2021-03-30 
18:51:07.000000000 +0200
@@ -51,7 +51,7 @@
                        break;
        }
 
-       age = now.tv_sec - curr_sec;
+       age = (global_now >> 32) - curr_sec;
        if (unlikely(age > 1))
                return 0;
 
@@ -94,7 +94,7 @@
                        break;
        }
 
-       age = now.tv_sec - curr_sec;
+       age = (global_now >> 32) - curr_sec;
        if (unlikely(age > 1))
                curr = 0;
        else {
@@ -141,7 +141,7 @@
                        break;
        }
 
-       age = now.tv_sec - curr_sec;
+       age = (global_now >> 32) - curr_sec;
        if (unlikely(age > 1))
                curr = 0;
        else {
@@ -163,7 +163,7 @@
 /* Reads a frequency counter taking history into account for missing time in
  * current period. The period has to be passed in number of ticks and must
  * match the one used to feed the counter. The counter value is reported for
- * current date (now_ms). The return value has the same precision as one input
+ * current global date. The return value has the same precision as one input
  * data sample, so low rates over the period will be inaccurate but still
  * appropriate for max checking. One trick we use for low values is to 
specially
  * handle the case where the rate is between 0 and 1 in order to avoid flapping
@@ -200,7 +200,7 @@
                        break;
        };
 
-       remain = curr_tick + period - now_ms;
+       remain = curr_tick + period - global_now_ms;
        if (unlikely((int)remain < 0)) {
                /* We're past the first period, check if we can still report a
                 * part of last period or if we're too far away.
@@ -247,7 +247,7 @@
                        break;
        };
 
-       remain = curr_tick + period - now_ms;
+       remain = curr_tick + period - global_now_ms;
        if (likely((int)remain < 0)) {
                /* We're past the first period, check if we can still report a
                 * part of last period or if we're too far away.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/hlua.c 
new/haproxy-2.3.9+git1.afb63bc04/src/hlua.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/hlua.c 2021-03-16 15:49:34.000000000 
+0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/hlua.c 2021-03-30 18:51:07.000000000 
+0200
@@ -283,19 +283,17 @@
        return lua_tostring(L, -1);
 }
 
-__LJMP static const char *hlua_traceback(lua_State *L)
+__LJMP const char *hlua_traceback(lua_State *L, const char* sep)
 {
        lua_Debug ar;
        int level = 0;
        struct buffer *msg = get_trash_chunk();
-       int filled = 0;
 
        while (lua_getstack(L, level++, &ar)) {
 
                /* Add separator */
-               if (filled)
-                       chunk_appendf(msg, ", ");
-               filled = 1;
+               if (b_data(msg))
+                       chunk_appendf(msg, "%s", sep);
 
                /* Fill fields:
                 * 'S': fills in the fields source, short_src, linedefined, 
lastlinedefined, and what;
@@ -307,9 +305,9 @@
 
                /* Append code localisation */
                if (ar.currentline > 0)
-                       chunk_appendf(msg, "%s:%d ", ar.short_src, 
ar.currentline);
+                       chunk_appendf(msg, "%s:%d: ", ar.short_src, 
ar.currentline);
                else
-                       chunk_appendf(msg, "%s ", ar.short_src);
+                       chunk_appendf(msg, "%s: ", ar.short_src);
 
                /*
                 * Get function name
@@ -319,13 +317,13 @@
                 * or "main" for main code.
                 */
                if (*ar.namewhat != '\0' && ar.name != NULL)  /* is there a 
name from code? */
-                       chunk_appendf(msg, "%s '%s'", ar.namewhat, ar.name);  
/* use it */
+                       chunk_appendf(msg, "in %s '%s'", ar.namewhat, ar.name); 
 /* use it */
 
                else if (*ar.what == 'm')  /* "main", the code is not executed 
in a function */
-                       chunk_appendf(msg, "main chunk");
+                       chunk_appendf(msg, "in main chunk");
 
                else if (*ar.what != 'C')  /* for Lua functions, use 
<file:line> */
-                       chunk_appendf(msg, "C function line %d", 
ar.linedefined);
+                       chunk_appendf(msg, "in function line %d", 
ar.linedefined);
 
                else  /* nothing left... */
                        chunk_appendf(msg, "?");
@@ -1271,7 +1269,7 @@
                msg = lua_tostring(lua->T, -1);
                lua_settop(lua->T, 0); /* Empty the stack. */
                lua_pop(lua->T, 1);
-               trace = hlua_traceback(lua->T);
+               trace = hlua_traceback(lua->T, ", ");
                if (msg)
                        lua_pushfstring(lua->T, "runtime error: %s from %s", 
msg, trace);
                else
@@ -6277,6 +6275,7 @@
        hlua = pool_alloc(pool_head_hlua);
        if (!hlua)
                WILL_LJMP(luaL_error(L, "Lua out of memory error."));
+       HLUA_INIT(hlua);
 
        task = task_new(MAX_THREADS_MASK);
        if (!task)
@@ -6317,11 +6316,15 @@
         * Lua initialization cause 5% performances loss.
         */
        if (!stream->hlua) {
-               stream->hlua = pool_alloc(pool_head_hlua);
-               if (!stream->hlua) {
+               struct hlua *hlua;
+
+               hlua = pool_alloc(pool_head_hlua);
+               if (!hlua) {
                        SEND_ERR(stream->be, "Lua converter '%s': can't 
initialize Lua context.\n", fcn->name);
                        return 0;
                }
+               HLUA_INIT(hlua);
+               stream->hlua = hlua;
                if (!hlua_ctx_init(stream->hlua, stream->task, 0)) {
                        SEND_ERR(stream->be, "Lua converter '%s': can't 
initialize Lua context.\n", fcn->name);
                        return 0;
@@ -6450,11 +6453,15 @@
         * Lua initialization cause 5% performances loss.
         */
        if (!stream->hlua) {
-               stream->hlua = pool_alloc(pool_head_hlua);
-               if (!stream->hlua) {
+               struct hlua *hlua;
+
+               hlua = pool_alloc(pool_head_hlua);
+               if (!hlua) {
                        SEND_ERR(stream->be, "Lua sample-fetch '%s': can't 
initialize Lua context.\n", fcn->name);
                        return 0;
                }
+               hlua->T = NULL;
+               stream->hlua = hlua;
                if (!hlua_ctx_init(stream->hlua, stream->task, 0)) {
                        SEND_ERR(stream->be, "Lua sample-fetch '%s': can't 
initialize Lua context.\n", fcn->name);
                        return 0;
@@ -6745,12 +6752,16 @@
         * Lua initialization cause 5% performances loss.
         */
        if (!s->hlua) {
-               s->hlua = pool_alloc(pool_head_hlua);
-               if (!s->hlua) {
+               struct hlua *hlua;
+
+               hlua = pool_alloc(pool_head_hlua);
+               if (!hlua) {
                        SEND_ERR(px, "Lua action '%s': can't initialize Lua 
context.\n",
                                 rule->arg.hlua_rule->fcn.name);
                        goto end;
                }
+               HLUA_INIT(hlua);
+               s->hlua = hlua;
                if (!hlua_ctx_init(s->hlua, s->task, 0)) {
                        SEND_ERR(px, "Lua action '%s': can't initialize Lua 
context.\n",
                                 rule->arg.hlua_rule->fcn.name);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/http_fetch.c 
new/haproxy-2.3.9+git1.afb63bc04/src/http_fetch.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/http_fetch.c   2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/http_fetch.c   2021-03-30 
18:51:07.000000000 +0200
@@ -999,19 +999,30 @@
 
 /* Fetch an HTTP header's IP value. takes a mandatory argument of type string
  * and an optional one of type int to designate a specific occurrence.
- * It returns an IPv4 or IPv6 address.
+ * It returns an IPv4 or IPv6 address. Addresses surrounded by invalid chars
+ * are rejected. However IPv4 addresses may be followed with a colon and a
+ * valid port number.
  */
 static int smp_fetch_hdr_ip(const struct arg *args, struct sample *smp, const 
char *kw, void *private)
 {
-       int ret;
        struct buffer *temp = get_trash_chunk();
+       int ret, len;
+       int port;
 
        while ((ret = smp_fetch_hdr(args, smp, kw, private)) > 0) {
                if (smp->data.u.str.data < temp->size - 1) {
                        memcpy(temp->area, smp->data.u.str.area,
                               smp->data.u.str.data);
                        temp->area[smp->data.u.str.data] = '\0';
-                       if (url2ipv4((char *) temp->area, &smp->data.u.ipv4)) {
+                       len = url2ipv4((char *) temp->area, &smp->data.u.ipv4);
+                       if (len == smp->data.u.str.data) {
+                               /* plain IPv4 address */
+                               smp->data.type = SMP_T_IPV4;
+                               break;
+                       } else if (len > 0 && temp->area[len] == ':' &&
+                                  strl2irc(temp->area + len + 1, 
smp->data.u.str.data - len - 1, &port) == 0 &&
+                                  port >= 0 && port <= 65535) {
+                               /* IPv4 address suffixed with ':' followed by a 
valid port number */
                                smp->data.type = SMP_T_IPV4;
                                break;
                        } else if (inet_pton(AF_INET6, temp->area, 
&smp->data.u.ipv6)) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/mux_fcgi.c 
new/haproxy-2.3.9+git1.afb63bc04/src/mux_fcgi.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/mux_fcgi.c     2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/mux_fcgi.c     2021-03-30 
18:51:07.000000000 +0200
@@ -2957,13 +2957,14 @@
                conn_in_list = conn->flags & CO_FL_LIST_MASK;
                if (conn_in_list)
                        MT_LIST_DEL(&conn->list);
+
+               HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conns[tid].takeover_lock);
        } else {
                /* we're certain the connection was not in an idle list */
                conn = fconn->conn;
                TRACE_ENTER(FCGI_EV_FCONN_WAKE, conn);
                conn_in_list = 0;
        }
-       HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conns[tid].takeover_lock);
 
        if (!(fconn->wait_event.events & SUB_RETRY_SEND))
                ret = fcgi_send(fconn);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/mux_h1.c 
new/haproxy-2.3.9+git1.afb63bc04/src/mux_h1.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/mux_h1.c       2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/mux_h1.c       2021-03-30 
18:51:07.000000000 +0200
@@ -2663,6 +2663,9 @@
 {
        struct h1c *h1c = conn->ctx;
 
+       if (conn->flags & CO_FL_SOCK_WR_SH)
+               return;
+
        TRACE_ENTER(H1_EV_STRM_SHUT, conn, h1c->h1s);
        conn_xprt_shutw(conn);
        conn_sock_shutw(conn, (mode == CS_SHW_NORMAL));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/payload.c 
new/haproxy-2.3.9+git1.afb63bc04/src/payload.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/payload.c      2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/payload.c      2021-03-30 
18:51:07.000000000 +0200
@@ -984,7 +984,7 @@
        }
        max = global.tune.bufsize;
        if (!head)
-               return 0;
+               goto too_short;
 
        if (len_offset + len_size > data)
                goto too_short;
@@ -1046,7 +1046,7 @@
        }
        max = global.tune.bufsize;
        if (!head)
-               return 0;
+               goto too_short;
 
        if (buf_size > max || buf_offset + buf_size > max) {
                /* will never match */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/proto_uxdg.c 
new/haproxy-2.3.9+git1.afb63bc04/src/proto_uxdg.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/proto_uxdg.c   1970-01-01 
01:00:00.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/proto_uxdg.c   2021-03-30 
18:51:07.000000000 +0200
@@ -0,0 +1,151 @@
+/*
+ * DGRAM protocol layer on top of AF_UNIX
+ *
+ * Copyright 2020 HAProxy Technologies, Emeric Brun <[email protected]>
+ *
+ * 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 <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <haproxy/fd.h>
+#include <haproxy/listener.h>
+#include <haproxy/log.h>
+#include <haproxy/namespace.h>
+#include <haproxy/protocol.h>
+#include <haproxy/sock.h>
+#include <haproxy/sock_unix.h>
+
+static int uxdg_bind_listener(struct listener *listener, char *errmsg, int 
errlen);
+static void uxdg_enable_listener(struct listener *listener);
+static void uxdg_disable_listener(struct listener *listener);
+static int uxdg_suspend_receiver(struct receiver *rx);
+
+/* Note: must not be declared <const> as its list will be overwritten */
+struct protocol proto_uxdg = {
+       .name           = "uxdg",
+
+       /* connection layer */
+       .ctrl_type      = SOCK_DGRAM,
+       .listen         = uxdg_bind_listener,
+       .enable         = uxdg_enable_listener,
+       .disable        = uxdg_disable_listener,
+       .add            = default_add_listener,
+       .unbind         = default_unbind_listener,
+       .suspend        = default_suspend_listener,
+       .resume         = default_resume_listener,
+
+       /* binding layer */
+       .rx_suspend     = uxdg_suspend_receiver,
+
+       /* address family */
+       .fam            = &proto_fam_unix,
+
+       /* socket layer */
+       .sock_type      = SOCK_DGRAM,
+       .sock_prot      = 0,
+       .rx_enable      = sock_enable,
+       .rx_disable     = sock_disable,
+       .rx_unbind      = sock_unbind,
+       .receivers      = LIST_HEAD_INIT(proto_uxdg.receivers),
+       .nb_receivers   = 0,
+};
+
+INITCALL1(STG_REGISTER, protocol_register, &proto_uxdg);
+
+/* This function tries to bind dgram unix socket listener. It may return a 
warning or
+ * an error message in <errmsg> if the message is at most <errlen> bytes long
+ * (including '\0'). Note that <errmsg> may be NULL if <errlen> is also zero.
+ * The return value is composed from ERR_ABORT, ERR_WARN,
+ * ERR_ALERT, ERR_RETRYABLE and ERR_FATAL. ERR_NONE indicates that everything
+ * was alright and that no message was returned. ERR_RETRYABLE means that an
+ * error occurred but that it may vanish after a retry (eg: port in use), and
+ * ERR_FATAL indicates a non-fixable error. ERR_WARN and ERR_ALERT do not alter
+ * the meaning of the error, but just indicate that a message is present which
+ * should be displayed with the respective level. Last, ERR_ABORT indicates
+ * that it's pointless to try to start other listeners. No error message is
+ * returned if errlen is NULL.
+ */
+int uxdg_bind_listener(struct listener *listener, char *errmsg, int errlen)
+{
+       int err = ERR_NONE;
+       char *msg = NULL;
+
+       /* ensure we never return garbage */
+       if (errlen)
+               *errmsg = 0;
+
+       if (listener->state != LI_ASSIGNED)
+               return ERR_NONE; /* already bound */
+
+       if (!(listener->rx.flags & RX_F_BOUND)) {
+               msg = "receiving socket not bound";
+               goto uxdg_return;
+       }
+
+       listener_set_state(listener, LI_LISTEN);
+
+ uxdg_return:
+       if (msg && errlen) {
+               const char *path = ((struct sockaddr_un 
*)&listener->rx.addr)->sun_path;
+                snprintf(errmsg, errlen, "%s [%s]", msg, path);
+       }
+       return err;
+}
+
+/* Enable receipt of incoming connections for listener <l>. The receiver must
+ * still be valid.
+ */
+static void uxdg_enable_listener(struct listener *l)
+{
+       fd_want_recv_safe(l->rx.fd);
+}
+
+/* Disable receipt of incoming connections for listener <l>. The receiver must
+ * still be valid.
+ */
+static void uxdg_disable_listener(struct listener *l)
+{
+       fd_stop_recv(l->rx.fd);
+}
+
+/* Suspend a receiver. Returns < 0 in case of failure, 0 if the receiver
+ * was totally stopped, or > 0 if correctly suspended. Nothing is done for
+ * plain unix sockets since currently it's the new process which handles
+ * the renaming. Abstract sockets are completely unbound and closed so
+ * there's no need to stop the poller.
+ */
+static int uxdg_suspend_receiver(struct receiver *rx)
+{
+        struct listener *l = LIST_ELEM(rx, struct listener *, rx);
+
+        if (((struct sockaddr_un *)&rx->addr)->sun_path[0])
+                return 1;
+
+        /* Listener's lock already held. Call lockless version of
+         * unbind_listener. */
+        do_unbind_listener(l);
+        return 0;
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ * End:
+ */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/ssl_crtlist.c 
new/haproxy-2.3.9+git1.afb63bc04/src/ssl_crtlist.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/ssl_crtlist.c  2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/ssl_crtlist.c  2021-03-30 
18:51:07.000000000 +0200
@@ -311,7 +311,7 @@
  *  <crt_path> is a ptr in <line>
  *  Return an error code
  */
-int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry 
*entry, const char *file, int linenum, char **err)
+int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry 
*entry, const char *file, int linenum, int from_cli, char **err)
 {
        int cfgerr = 0;
        int arg, newarg, cur_arg, i, ssl_b = 0, ssl_e = 0;
@@ -395,13 +395,14 @@
                        goto error;
                }
        }
+
        cur_arg = ssl_b ? ssl_b : 1;
        while (cur_arg < ssl_e) {
                newarg = 0;
                for (i = 0; ssl_bind_kws[i].kw != NULL; i++) {
                        if (strcmp(ssl_bind_kws[i].kw, args[cur_arg]) == 0) {
                                newarg = 1;
-                               cfgerr |= ssl_bind_kws[i].parse(args, cur_arg, 
NULL, ssl_conf, err);
+                               cfgerr |= ssl_bind_kws[i].parse(args, cur_arg, 
NULL, ssl_conf, from_cli, err);
                                if (cur_arg + 1 + ssl_bind_kws[i].skip > ssl_e) 
{
                                        memprintf(err, "parsing [%s:%d]: ssl 
args out of '[]' for %s",
                                                  file, linenum, args[cur_arg]);
@@ -512,7 +513,7 @@
                        goto error;
                }
 
-               cfgerr |= crtlist_parse_line(thisline, &crt_path, entry, file, 
linenum, err);
+               cfgerr |= crtlist_parse_line(thisline, &crt_path, entry, file, 
linenum, 0, err);
                if (cfgerr & ERR_CODE)
                        goto error;
 
@@ -1216,7 +1217,7 @@
                        goto error;
                }
                /* cert_path is filled here */
-               cfgerr |= crtlist_parse_line(payload, &cert_path, entry, "CLI", 
1, &err);
+               cfgerr |= crtlist_parse_line(payload, &cert_path, entry, "CLI", 
1, 1, &err);
                if (cfgerr & ERR_CODE)
                        goto error;
        } else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/ssl_sock.c 
new/haproxy-2.3.9+git1.afb63bc04/src/ssl_sock.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/ssl_sock.c     2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/ssl_sock.c     2021-03-30 
18:51:07.000000000 +0200
@@ -300,11 +300,16 @@
        return NULL;
 }
 
-int ssl_store_load_locations_file(char *path)
+int ssl_store_load_locations_file(char *path, int create_if_none)
 {
-       if (ssl_store_get0_locations_file(path) == NULL) {
+       X509_STORE *store = ssl_store_get0_locations_file(path);
+
+       /* If this function is called by the CLI, we should not call the
+        * X509_STORE_load_locations function because it performs forbidden disk
+        * accesses. */
+       if (!store && create_if_none) {
                struct cafile_entry *ca_e;
-               X509_STORE *store = X509_STORE_new();
+               store = X509_STORE_new();
                if (X509_STORE_load_locations(store, path, NULL)) {
                        int pathlen;
                        pathlen = strlen(path);
@@ -313,13 +318,13 @@
                                memcpy(ca_e->path, path, pathlen + 1);
                                ca_e->ca_store = store;
                                ebst_insert(&cafile_tree, &ca_e->node);
-                               return 1;
                        }
+               } else {
+                       X509_STORE_free(store);
+                       store = NULL;
                }
-               X509_STORE_free(store);
-               return 0;
        }
-       return 1;
+       return (store != NULL);
 }
 
 /* mimic what X509_STORE_load_locations do with store_ctx */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/stats.c 
new/haproxy-2.3.9+git1.afb63bc04/src/stats.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/stats.c        2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/stats.c        2021-03-30 
18:51:07.000000000 +0200
@@ -1073,13 +1073,13 @@
                    strcmp(field_str(stats, ST_F_STATUS), "DOWN (agent)") == 0) 
{
                        style = "down";
                }
-               else if (strcmp(field_str(stats, ST_F_STATUS), "DOWN ") == 0) {
+               else if (strncmp(field_str(stats, ST_F_STATUS), "DOWN ", 
strlen("DOWN ")) == 0) {
                        style = "going_up";
                }
                else if (strcmp(field_str(stats, ST_F_STATUS), "DRAIN") == 0) {
                        style = "draining";
                }
-               else if (strcmp(field_str(stats, ST_F_STATUS), "NOLB ") == 0) {
+               else if (strncmp(field_str(stats, ST_F_STATUS), "NOLB ", 
strlen("NOLB ")) == 0) {
                        style = "going_down";
                }
                else if (strcmp(field_str(stats, ST_F_STATUS), "NOLB") == 0) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/thread.c 
new/haproxy-2.3.9+git1.afb63bc04/src/thread.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/thread.c       2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/thread.c       2021-03-30 
18:51:07.000000000 +0200
@@ -48,13 +48,15 @@
 #endif
 
 /* Marks the thread as harmless until the last thread using the rendez-vous
- * point quits. Given that we can wait for a long time, sched_yield() is used
- * when available to offer the CPU resources to competing threads if needed.
+ * point quits, excluding the current one. Thus an isolated thread may be 
safely
+ * marked as harmless. Given that we can wait for a long time, sched_yield() is
+ * used when available to offer the CPU resources to competing threads if
+ * needed.
  */
 void thread_harmless_till_end()
 {
                _HA_ATOMIC_OR(&threads_harmless_mask, tid_bit);
-               while (threads_want_rdv_mask & all_threads_mask) {
+               while (threads_want_rdv_mask & ~tid_bit) {
                        ha_thread_relax();
                }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/time.c 
new/haproxy-2.3.9+git1.afb63bc04/src/time.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/time.c 2021-03-16 15:49:34.000000000 
+0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/time.c 2021-03-30 18:51:07.000000000 
+0200
@@ -15,6 +15,7 @@
 
 #include <haproxy/api.h>
 #include <haproxy/time.h>
+#include <haproxy/ticks.h>
 #include <haproxy/tools.h>
 
 THREAD_LOCAL unsigned int   ms_left_scaled;  /* milliseconds left for current 
second (0..2^32-1) */
@@ -28,7 +29,8 @@
 THREAD_LOCAL struct timeval after_poll;      /* system date after leaving 
poll() */
 
 static THREAD_LOCAL struct timeval tv_offset;  /* per-thread time ofsset 
relative to global time */
-static volatile unsigned long long global_now; /* common date between all 
threads (32:32) */
+volatile unsigned long long global_now;      /* common date between all 
threads (32:32) */
+volatile unsigned int global_now_ms;         /* common date in milliseconds 
(may wrap) */
 
 static THREAD_LOCAL unsigned int iso_time_sec;     /* last iso time value for 
this thread */
 static THREAD_LOCAL char         iso_time_str[34]; /* ISO time representation 
of gettimeofday() */
@@ -177,6 +179,7 @@
 {
        struct timeval adjusted, deadline, tmp_now, tmp_adj;
        unsigned int   curr_sec_ms;     /* millisecond of current second 
(0..999) */
+       unsigned int old_now_ms, new_now_ms;
        unsigned long long old_now;
        unsigned long long new_now;
 
@@ -260,6 +263,15 @@
         */
        ms_left_scaled = (999U - curr_sec_ms) * 4294967U;
        now_ms = now.tv_sec * 1000 + curr_sec_ms;
+
+       /* update the global current millisecond */
+       old_now_ms = global_now_ms;
+       do {
+               new_now_ms = old_now_ms;
+               if (tick_is_lt(new_now_ms, now_ms) || !new_now_ms)
+                       new_now_ms = now_ms;
+       }  while (!_HA_ATOMIC_CAS(&global_now_ms, &old_now_ms, new_now_ms));
+
        return;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/haproxy-2.3.7+git0.2d39ce334/src/tools.c 
new/haproxy-2.3.9+git1.afb63bc04/src/tools.c
--- old/haproxy-2.3.7+git0.2d39ce334/src/tools.c        2021-03-16 
15:49:34.000000000 +0100
+++ new/haproxy-2.3.9+git1.afb63bc04/src/tools.c        2021-03-30 
18:51:07.000000000 +0200
@@ -1381,7 +1381,9 @@
 
 
 /*
- * Parse IPv4 address found in url.
+ * Parse IPv4 address found in url. Return the number of bytes parsed. It
+ * expects exactly 4 numbers between 0 and 255 delimited by dots, and returns
+ * zero in case of mismatch.
  */
 int url2ipv4(const char *addr, struct in_addr *dst)
 {
@@ -1394,9 +1396,10 @@
        *(tp = tmp) = 0;
 
        while (*addr) {
-               unsigned char digit = (ch = *addr++) - '0';
+               unsigned char digit = (ch = *addr) - '0';
                if (digit > 9 && ch != '.')
                        break;
+               addr++;
                if (digit <= 9) {
                        u_int new = *tp * 10 + digit;
                        if (new > 255)
@@ -1420,7 +1423,7 @@
                return 0;
 
        memcpy(&dst->s_addr, tmp, 4);
-       return addr-cp-1;
+       return addr - cp;
 }
 
 /*

Reply via email to