Version in base suite: 1.3.15.2-2~lenny1 Version in overlay suite: (not present) Base version: haproxy_1.3.15.2-2~lenny1 Target version: haproxy_1.3.15.2-2+lenny2 Base file: /org/ftp.debian.org/ftp/pool/main/h/haproxy/haproxy_1.3.15.2-2~lenny1.dsc Target file: /org/ftp.debian.org/queue/p-u-new/haproxy_1.3.15.2-2+lenny2.dsc debian/patches/0001-BUG-disable-buffer-read-timeout-when-reading-stats.patch | 29 + debian/patches/0004-BUG-use_backend-would-not-correctly-consider-unless.patch | 28 + debian/patches/0006-BUG-fix-segfault-with-url_param-check_post.patch | 86 +++++ debian/patches/0007-BUG-server-timeout-was-not-considered-in-some-circum.patch | 46 ++ debian/patches/0008-BUG-ev_sepoll-closed-file-descriptors-could-persist-.patch | 51 +++ debian/patches/0009-BUG-maintain_proxies-must-not-disable-backends.patch | 28 + debian/patches/0013-BUG-do-not-release-the-connection-slot-during-a-retr.patch | 37 ++ debian/patches/0014-BUG-dynamic-connection-throttling-could-return-a-max.patch | 33 ++ debian/patches/0016-BUG-do-not-try-to-pause-backends-during-reload.patch | 79 +++++ debian/patches/0017-BUG-ensure-that-listeners-from-disabled-proxies-are-.patch | 97 ++++++ debian/patches/0018-BUG-acl-related-keywords-are-not-allowed-in-defaults.patch | 82 +++++ debian/patches/0021-BUG-cookie-capture-is-declared-in-the-frontend-but-c.patch | 77 ++++ debian/patches/0024-BUG-critical-errors-should-be-reported-even-in-daemo.patch | 47 +++ debian/patches/0025-BUG-do-not-dequeue-requests-on-a-dead-server.patch | 43 ++ debian/patches/0026-BUG-do-not-dequeue-the-backend-s-pending-connections.patch | 94 ++++++ debian/patches/0028-BUG-Fix-listen-more-of-2-couples-ip-port.patch | 31 ++ debian/patches/0030-CRITICAL-fix-server-state-tracking-it-was-O-n-instea.patch | 58 +++ debian/patches/0031-BUG-option-transparent-is-for-backend-not-frontend.patch | 123 +++++++ debian/patches/0032-BUG-we-must-not-exit-if-protocol-binding-only-return.patch | 37 ++ debian/patches/0033-BUG-inform-the-user-when-root-is-expected-but-not-se.patch | 40 ++ debian/patches/0035-BUG-the-source-keyword-must-first-clear-optional-set.patch | 35 ++ debian/patches/0036-BUG-global.tune.maxaccept-must-be-limited-even-in-mo.patch | 63 ++++ debian/patches/0037-BUG-typo-in-timeout-error-reporting-report-res-and-n.patch | 26 + debian/patches/0042-BUG-server-check-intervals-must-not-be-null.patch | 99 ++++++ debian/patches/0043-BUG-check-for-global.maxconn-before-doing-accept.patch | 46 ++ debian/patches/0047-BUG-stats-total-and-lbtot-are-unsigned.patch | 63 ++++ debian/patches/0049-MEDIUM-ensure-we-don-t-recursively-call-pool_gc2.patch | 50 +++ debian/patches/0050-CRITICAL-uninitialized-response-field-can-sometimes-.patch | 39 ++ debian/patches/0052-BUG-O-1-pollers-should-check-their-FD-before-closing.patch | 155 ++++++++++ debian/patches/0057-BUG-ensure-that-we-correctly-re-start-old-process-in.patch | 39 ++ debian/patches/0059-BUG-stream_sock-don-t-stop-reading-when-the-poller-r.patch | 61 +++ debian/patches/acl-in-default.patch | 77 ---- debian/patches/closed-fd-remove.patch | 46 -- debian/patches/connection-slot-during-retry.patch | 32 -- debian/patches/cookie-capture-check.patch | 72 ---- debian/patches/dead-servers-queue.patch | 58 --- debian/patches/do-not-pause-backends-on-reload.patch | 133 -------- debian/patches/segfault-url_param+check_post.patch | 80 ----- debian/patches/server-timeout.patch | 41 -- debian/patches/srv_dynamic_maxconn.patch | 28 - debian/patches/use_backend-consider-unless.patch | 23 - haproxy-1.3.15.2/debian/changelog | 37 ++ haproxy-1.3.15.2/debian/patches/series | 41 ++ 43 files changed, 1890 insertions(+), 600 deletions(-) diff -u haproxy-1.3.15.2/debian/changelog haproxy-1.3.15.2/debian/changelog --- haproxy-1.3.15.2/debian/changelog +++ haproxy-1.3.15.2/debian/changelog @@ -1,3 +1,40 @@ +haproxy (1.3.15.2-2+lenny2) stable; urgency=low + + * Merge critical bug fixes that are fixed upsteam. + 0001-BUG-disable-buffer-read-timeout-when-reading-stats.patch + 0004-BUG-use_backend-would-not-correctly-consider-unless.patch + 0006-BUG-fix-segfault-with-url_param-check_post.patch + 0007-BUG-server-timeout-was-not-considered-in-some-circum.patch + 0008-BUG-ev_sepoll-closed-file-descriptors-could-persist-.patch + 0009-BUG-maintain_proxies-must-not-disable-backends.patch + 0013-BUG-do-not-release-the-connection-slot-during-a-retr.patch + 0014-BUG-dynamic-connection-throttling-could-return-a-max.patch + 0016-BUG-do-not-try-to-pause-backends-during-reload.patch + 0017-BUG-ensure-that-listeners-from-disabled-proxies-are-.patch + 0018-BUG-acl-related-keywords-are-not-allowed-in-defaults.patch + 0021-BUG-cookie-capture-is-declared-in-the-frontend-but-c.patch + 0024-BUG-critical-errors-should-be-reported-even-in-daemo.patch + 0025-BUG-do-not-dequeue-requests-on-a-dead-server.patch + 0026-BUG-do-not-dequeue-the-backend-s-pending-connections.patch + 0028-BUG-Fix-listen-more-of-2-couples-ip-port.patch + 0030-CRITICAL-fix-server-state-tracking-it-was-O-n-instea.patch + 0031-BUG-option-transparent-is-for-backend-not-frontend.patch + 0032-BUG-we-must-not-exit-if-protocol-binding-only-return.patch + 0033-BUG-inform-the-user-when-root-is-expected-but-not-se.patch + 0035-BUG-the-source-keyword-must-first-clear-optional-set.patch + 0036-BUG-global.tune.maxaccept-must-be-limited-even-in-mo.patch + 0037-BUG-typo-in-timeout-error-reporting-report-res-and-n.patch + 0042-BUG-server-check-intervals-must-not-be-null.patch + 0043-BUG-check-for-global.maxconn-before-doing-accept.patch + 0047-BUG-stats-total-and-lbtot-are-unsigned.patch + 0049-MEDIUM-ensure-we-don-t-recursively-call-pool_gc2.patch + 0050-CRITICAL-uninitialized-response-field-can-sometimes-.patch + 0052-BUG-O-1-pollers-should-check-their-FD-before-closing.patch + 0057-BUG-ensure-that-we-correctly-re-start-old-process-in.patch + 0059-BUG-stream_sock-don-t-stop-reading-when-the-poller-r.patch + + -- Arnaud Cornet Thu, 29 Oct 2009 22:03:28 +0000 + haproxy (1.3.15.2-2~lenny1) testing-proposed-updates; urgency=low * Rebuild for lenny to circumvent pcre3 shlibs bump. reverted: --- haproxy-1.3.15.2/debian/patches/server-timeout.patch +++ haproxy-1.3.15.2.orig/debian/patches/server-timeout.patch @@ -1,41 +0,0 @@ -commit df82605d3e73573ae842a1ddaf418997bef33274 -Author: Willy Tarreau -Date: Mon Aug 11 10:35:07 2008 +0200 - - [BUG] server timeout was not considered in some circumstances - - Due to a copy-paste typo, the client timeout was refreshed instead - of the server's when waiting for server response. This means that - the server's timeout remained eternity. - - (cherry picked from commit 9f1f24bb7fb8ebd6b43b5fee1bda0afbdbcb768e) - -diff --git a/src/stream_sock.c b/src/stream_sock.c -index 08cc65b..8bfc55b 100644 ---- a/src/stream_sock.c -+++ b/src/stream_sock.c -@@ -174,7 +174,7 @@ int stream_sock_read(int fd) { - * have at least read something. - */ - -- if (b->flags & BF_PARTIAL_READ) { -+ if (b->flags & BF_PARTIAL_READ && tv_isset(&b->rex)) { - if (tv_add_ifset(&b->rex, &now, &b->rto)) - goto out_wakeup; - out_eternity: -@@ -330,13 +330,13 @@ int stream_sock_write(int fd) { - * written something. - */ - -- if (b->flags & BF_PARTIAL_WRITE) { -+ if (b->flags & BF_PARTIAL_WRITE && tv_isset(&b->wex)) { - if (tv_add_ifset(&b->wex, &now, &b->wto)) { - /* FIXME: to prevent the client from expiring read timeouts during writes, - * we refresh it. A solution would be to merge read+write timeouts into a - * unique one, although that needs some study particularly on full-duplex - * TCP connections. */ -- if (!(b->flags & BF_SHUTR_STATUS)) -+ if (!(b->flags & BF_SHUTR_STATUS) && tv_isset(&b->rex)) - b->rex = b->wex; - goto out_wakeup; - } reverted: --- haproxy-1.3.15.2/debian/patches/do-not-pause-backends-on-reload.patch +++ haproxy-1.3.15.2.orig/debian/patches/do-not-pause-backends-on-reload.patch @@ -1,133 +0,0 @@ -Index: haproxy/include/proto/proxy.h -=================================================================== ---- haproxy.orig/include/proto/proxy.h 2008-12-30 18:13:53.000000000 +0100 -+++ haproxy/include/proto/proxy.h 2008-12-30 18:14:05.000000000 +0100 -@@ -30,6 +30,7 @@ - void maintain_proxies(struct timeval *next); - void soft_stop(void); - void pause_proxy(struct proxy *p); -+void stop_proxy(struct proxy *p); - void pause_proxies(void); - void listen_proxies(void); - -Index: haproxy/src/cfgparse.c -=================================================================== ---- haproxy.orig/src/cfgparse.c 2008-12-30 18:14:14.000000000 +0100 -+++ haproxy/src/cfgparse.c 2008-12-30 18:14:53.000000000 +0100 -@@ -2726,6 +2726,8 @@ - struct listener *listener; - - if (curproxy->state == PR_STSTOPPED) { -+ /* ensure we don't keep listeners uselessly bound */ -+ stop_proxy(curproxy); - curproxy = curproxy->next; - continue; - } -Index: haproxy/src/proxy.c -=================================================================== ---- haproxy.orig/src/proxy.c 2008-12-30 18:14:58.000000000 +0100 -+++ haproxy/src/proxy.c 2008-12-30 18:21:47.000000000 +0100 -@@ -352,14 +352,7 @@ - Warning("Proxy %s stopped.\n", p->id); - send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id); - -- for (l = p->listen; l != NULL; l = l->next) { -- unbind_listener(l); -- if (l->state >= LI_ASSIGNED) { -- delete_listener(l); -- listeners--; -- } -- } -- p->state = PR_STSTOPPED; -+ stop_proxy(p); - /* try to free more memory */ - pool_gc2(); - } -@@ -388,8 +381,8 @@ - tv_now(&now); /* else, the old time before select will be used */ - while (p) { - if (p->state != PR_STSTOPPED) { -- Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace); -- send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace); -+ Warning("Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); -+ send_log(p, LOG_WARNING, "Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); - tv_ms_add(&p->stop_time, &now, p->grace); - } - p = p->next; -@@ -422,6 +415,27 @@ - } - - /* -+ * This function completely stops a proxy and releases its listeners. It has -+ * to be called when going down in order to release the ports so that another -+ * process may bind to them. It must also be called on disabled proxies at the -+ * end of start-up. When all listeners are closed, the proxy is set to the -+ * PR_STSTOPPED state. -+ */ -+void stop_proxy(struct proxy *p) -+{ -+ struct listener *l; -+ -+ for (l = p->listen; l != NULL; l = l->next) { -+ unbind_listener(l); -+ if (l->state >= LI_ASSIGNED) { -+ delete_listener(l); -+ listeners--; -+ } -+ } -+ p->state = PR_STSTOPPED; -+} -+ -+/* - * This function temporarily disables listening so that another new instance - * can start listening. It is designed to be called upon reception of a - * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop -@@ -436,16 +450,17 @@ - p = proxy; - tv_now(&now); /* else, the old time before select will be used */ - while (p) { -- if (p->state != PR_STERROR && -+ if (p->cap & PR_CAP_FE && -+ p->state != PR_STERROR && - p->state != PR_STSTOPPED && - p->state != PR_STPAUSED) { -- Warning("Pausing proxy %s.\n", p->id); -- send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id); -+ Warning("Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); -+ send_log(p, LOG_WARNING, "Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); - pause_proxy(p); - if (p->state != PR_STPAUSED) { - err |= 1; -- Warning("Proxy %s failed to enter pause mode.\n", p->id); -- send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id); -+ Warning("%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); -+ send_log(p, LOG_WARNING, "%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); - } - } - p = p->next; -@@ -472,8 +487,8 @@ - tv_now(&now); /* else, the old time before select will be used */ - while (p) { - if (p->state == PR_STPAUSED) { -- Warning("Enabling proxy %s.\n", p->id); -- send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id); -+ Warning("Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); -+ send_log(p, LOG_WARNING, "Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); - - for (l = p->listen; l != NULL; l = l->next) { - if (listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0) { -@@ -491,10 +506,10 @@ - else - port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port); - -- Warning("Port %d busy while trying to enable proxy %s.\n", -- port, p->id); -- send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n", -- port, p->id); -+ Warning("Port %d busy while trying to enable %s %s.\n", -+ port, proxy_cap_str(p->cap), p->id); -+ send_log(p, LOG_WARNING, "Port %d busy while trying to enable %s %s.\n", -+ port, proxy_cap_str(p->cap), p->id); - /* Another port might have been enabled. Let's stop everything. */ - pause_proxy(p); - break; reverted: --- haproxy-1.3.15.2/debian/patches/connection-slot-during-retry.patch +++ haproxy-1.3.15.2.orig/debian/patches/connection-slot-during-retry.patch @@ -1,32 +0,0 @@ -commit 8262d8bd7fdb262c980bd70cb2931e51df07513f -Author: Willy Tarreau -Date: Sun Sep 14 17:40:09 2008 +0200 - - [BUG] do not release the connection slot during a retry - - A bug was introduced during last queue management fix. If a server - connection fails, the allocated connection slot is released, but it - will be needed again after the turn-around. This also causes more - connections than expected to go to the server because it appears to - have less connections than real. - - Many thanks to Rupert Fiasco, Mark Imbriaco, Cody Fauser, Brian - Gupta and Alexander Staubo for promptly providing configuration - and diagnosis elements to help reproduce this problem easily. - -diff --git a/src/proto_http.c b/src/proto_http.c -index 425fde6..7500798 100644 ---- a/src/proto_http.c -+++ b/src/proto_http.c -@@ -2686,10 +2686,8 @@ int process_srv(struct session *t) - } - else { - fd_delete(t->srv_fd); -- if (t->srv) { -+ if (t->srv) - t->srv->cur_sess--; -- sess_change_server(t, NULL); -- } - - if (!(req->flags & BF_WRITE_STATUS)) - conn_err = SN_ERR_SRVTO; // it was a connect timeout. reverted: --- haproxy-1.3.15.2/debian/patches/dead-servers-queue.patch +++ haproxy-1.3.15.2.orig/debian/patches/dead-servers-queue.patch @@ -1,58 +0,0 @@ -Index: haproxy/include/proto/queue.h -=================================================================== ---- haproxy.orig/include/proto/queue.h 2008-12-30 18:27:39.000000000 +0100 -+++ haproxy/include/proto/queue.h 2008-12-30 18:29:16.000000000 +0100 -@@ -64,10 +64,10 @@ - } - - /* returns 0 if nothing has to be done for server regarding queued connections, -- * and non-zero otherwise. Suited for and if/else usage. -+ * and non-zero otherwise. If the server is down, we only check its own queue. Suited for and if/else usage. - */ - static inline int may_dequeue_tasks(const struct server *s, const struct proxy *p) { -- return (s && (s->nbpend || p->nbpend) && -+ return (s && (s->nbpend || (p->nbpend && (s->state & SRV_RUNNING))) && - (!s->maxconn || s->cur_sess < srv_dynamic_maxconn(s))); - } - -Index: haproxy/src/queue.c -=================================================================== ---- haproxy.orig/src/queue.c 2008-12-30 18:29:24.000000000 +0100 -+++ haproxy/src/queue.c 2008-12-30 18:30:33.000000000 +0100 -@@ -89,6 +89,10 @@ - * returned. Note that neither nor may be NULL. - * Priority is given to the oldest request in the queue if both and - * have pending requests. This ensures that no request will be left unserved. -+ * The queue is not considered if the server is not RUNNING. The -+ * queue is still considered in this case, because if some connections remain -+ * there, it means that some requests have been forced there after it was seen -+ * down (eg: due to option persist). - * The session is immediately marked as "assigned", and both its and - * are set to , - */ -@@ -100,7 +104,7 @@ - ps = pendconn_from_srv(srv); - pp = pendconn_from_px(px); - /* we want to get the definitive pendconn in */ -- if (!pp) { -+ if (!pp || !(srv->state & SRV_RUNNING)) { - if (!ps) - return NULL; - } else { -Index: haproxy/src/session.c -=================================================================== ---- haproxy.orig/src/session.c 2008-12-30 18:30:52.000000000 +0100 -+++ haproxy/src/session.c 2008-12-30 18:35:40.000000000 +0100 -@@ -41,8 +41,10 @@ - - if (s->pend_pos) - pendconn_free(s->pend_pos); -- if (s->srv) /* there may be requests left pending in queue */ -- process_srv_queue(s->srv); -+ if (s->srv) { /* there may be requests left pending in queue */ -+ if (may_dequeue_tasks(s->srv, s->be)) -+ process_srv_queue(s->srv); -+ } - if (unlikely(s->srv_conn)) { - /* the session still has a reserved slot on a server, but - * it should normally be only the same as the one above, reverted: --- haproxy-1.3.15.2/debian/patches/cookie-capture-check.patch +++ haproxy-1.3.15.2.orig/debian/patches/cookie-capture-check.patch @@ -1,72 +0,0 @@ -commit bfca9e51b77b856593a3c4a3215a8e0397e7cdba -Author: Willy Tarreau -Date: Fri Oct 17 12:01:58 2008 +0200 - - [BUG] cookie capture is declared in the frontend but checked on the backend - - Cookie capture would only work by pure luck on the request but did - never work on responses since only the backend was checked. The fix - consists in always checking frontend for cookie captures. - (cherry picked from commit a83c5ba9315a7c47cda2698280b7e49a9d3eb374) - -diff --git a/src/proto_http.c b/src/proto_http.c -index 7500798..0a59fe1 100644 ---- a/src/proto_http.c -+++ b/src/proto_http.c -@@ -2009,7 +2009,7 @@ int process_cli(struct session *t) - * the fields will stay coherent and the URI will not move. - * This should only be performed in the backend. - */ -- if ((t->be->cookie_name || t->be->appsession_name || t->be->capture_name) -+ if ((t->be->cookie_name || t->be->appsession_name || t->fe->capture_name) - && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) - manage_client_side_cookies(t, req); - -@@ -3193,7 +3193,7 @@ int process_srv(struct session *t) - /* - * 4: check for server cookie. - */ -- if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name -+ if (t->be->cookie_name || t->be->appsession_name || t->fe->capture_name - || (t->be->options & PR_O_CHK_CACHE)) - manage_server_side_cookies(t, rep); - -@@ -4600,10 +4600,12 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr) - txn->flags |= TX_SCK_ANY; - - -- /* maybe we only wanted to see if there was a set-cookie */ -+ /* maybe we only wanted to see if there was a set-cookie. Note that -+ * the cookie capture is declared on the frontend. -+ */ - if (t->be->cookie_name == NULL && - t->be->appsession_name == NULL && -- t->be->capture_name == NULL) -+ t->fe->capture_name == NULL) - return; - - p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */ -@@ -4635,18 +4637,18 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr) - */ - - /* first, let's see if we want to capture it */ -- if (t->be->capture_name != NULL && -+ if (t->fe->capture_name != NULL && - txn->srv_cookie == NULL && -- (p4 - p1 >= t->be->capture_namelen) && -- memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) { -+ (p4 - p1 >= t->fe->capture_namelen) && -+ memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) { - int log_len = p4 - p1; - - if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) { - Alert("HTTP logging : out of memory.\n"); - } - -- if (log_len > t->be->capture_len) -- log_len = t->be->capture_len; -+ if (log_len > t->fe->capture_len) -+ log_len = t->fe->capture_len; - memcpy(txn->srv_cookie, p1, log_len); - txn->srv_cookie[log_len] = 0; - } reverted: --- haproxy-1.3.15.2/debian/patches/srv_dynamic_maxconn.patch +++ haproxy-1.3.15.2.orig/debian/patches/srv_dynamic_maxconn.patch @@ -1,28 +0,0 @@ -commit 819970098f134453c0934047b3bd3440b0996b55 -Author: Willy Tarreau -Date: Sun Sep 14 17:43:27 2008 +0200 - - [BUG] dynamic connection throttling could return a max of zero conns - - srv_dynamic_maxconn() is clearly documented as returning at least 1 - possible connection under throttling. But the computation was wrong, - the minimum 1 was divided and got lost in case of very low maxconns. - - Apply the MAX(1, max) before returning the result in order to ensure - that a newly appeared server will get some traffic. - -diff --git a/src/queue.c b/src/queue.c -index 178f187..905994a 100644 ---- a/src/queue.c -+++ b/src/queue.c -@@ -55,8 +55,8 @@ unsigned int srv_dynamic_maxconn(const struct server *s) - now.tv_sec < s->last_change + s->slowstart && - now.tv_sec >= s->last_change) { - unsigned int ratio; -- ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / s->slowstart); -- max = max * ratio / 100; -+ ratio = 100 * (now.tv_sec - s->last_change) / s->slowstart; -+ max = MAX(1, max * ratio / 100); - } - return max; - } reverted: --- haproxy-1.3.15.2/debian/patches/acl-in-default.patch +++ haproxy-1.3.15.2.orig/debian/patches/acl-in-default.patch @@ -1,77 +0,0 @@ -commit 1c90a6ec20946a713e9c93995a8e91ed3eeb9da4 -Author: Willy Tarreau -Date: Sun Oct 12 17:26:37 2008 +0200 - - [BUG] acl-related keywords are not allowed in defaults sections - - Using an ACL-related keyword in the defaults section causes a - segfault during parsing because the list headers are not initialized. - We must initialize list headers for default instance and reject - keywords relying on ACLs. - -diff --git a/src/cfgparse.c b/src/cfgparse.c -index b33800c..038915a 100644 ---- a/src/cfgparse.c -+++ b/src/cfgparse.c -@@ -516,6 +516,13 @@ static void init_default_instance() - defproxy.maxconn = cfg_maxpconn; - defproxy.conn_retries = CONN_RETRIES; - defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */ -+ -+ LIST_INIT(&defproxy.pendconns); -+ LIST_INIT(&defproxy.acl); -+ LIST_INIT(&defproxy.block_cond); -+ LIST_INIT(&defproxy.mon_fail_cond); -+ LIST_INIT(&defproxy.switching_rules); -+ - proxy_reset_timeouts(&defproxy); - } - -@@ -837,6 +844,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) - curproxy->state = PR_STNEW; - } - else if (!strcmp(args[0], "acl")) { /* add an ACL */ -+ if (curproxy == &defproxy) { -+ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); -+ return -1; -+ } -+ - err = invalid_char(args[1]); - if (err) { - Alert("parsing [%s:%d] : character '%c' is not permitted in acl name '%s'.\n", -@@ -1076,6 +1088,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) - int pol = ACL_COND_NONE; - struct acl_cond *cond; - -+ if (curproxy == &defproxy) { -+ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); -+ return -1; -+ } -+ - if (!strcmp(args[1], "if")) - pol = ACL_COND_IF; - else if (!strcmp(args[1], "unless")) -@@ -1099,6 +1116,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) - struct acl_cond *cond; - struct switching_rule *rule; - -+ if (curproxy == &defproxy) { -+ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); -+ return -1; -+ } -+ - if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL)) - return 0; - -@@ -1376,6 +1398,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) - } - } - else if (!strcmp(args[0], "monitor")) { -+ if (curproxy == &defproxy) { -+ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); -+ return -1; -+ } -+ - if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL)) - return 0; - reverted: --- haproxy-1.3.15.2/debian/patches/use_backend-consider-unless.patch +++ haproxy-1.3.15.2.orig/debian/patches/use_backend-consider-unless.patch @@ -1,23 +0,0 @@ -commit e05484f3ec2f2824c88d3a0c68a415111addadb1 -Author: Willy Tarreau -Date: Wed Jul 9 11:23:31 2008 +0200 - - [BUG] use_backend would not correctly consider "unless" - - A copy-paste typo made use_backend not correctly consider the "unless" - case, depending on the previous "block" rule. - (cherry picked from commit a8cfa34a9c011cecfaedfaf7d91de3e5f7f004a0) - -diff --git a/src/proto_http.c b/src/proto_http.c -index e36f4b0..f80129c 100644 ---- a/src/proto_http.c -+++ b/src/proto_http.c -@@ -1925,7 +1925,7 @@ int process_cli(struct session *t) - int ret; - - ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ); -- if (cond->pol == ACL_COND_UNLESS) -+ if (rule->cond->pol == ACL_COND_UNLESS) - ret = !ret; - - if (ret) { reverted: --- haproxy-1.3.15.2/debian/patches/closed-fd-remove.patch +++ haproxy-1.3.15.2.orig/debian/patches/closed-fd-remove.patch @@ -1,46 +0,0 @@ -commit 116f4105d4fc6fbd8f2d0a139f691973332176de -Author: Willy Tarreau -Date: Sat Aug 16 16:06:02 2008 +0200 - - [BUG] ev_sepoll: closed file descriptors could persist in the spec list - - If __fd_clo() was called on a file descriptor which was previously - disabled, it was not removed from the spec list. This apparently - could not happen on previous code because the TCP states prevented - this, but now it happens regularly. The effects are spec entries - stuck populated, leading to busy loops. - - (cherry picked from commit 7a52a5c4680477272b2f34eaf5896b85746e6fd6) - -diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c -index 800ac0b..db35423 100644 ---- a/src/ev_sepoll.c -+++ b/src/ev_sepoll.c -@@ -279,8 +279,7 @@ REGPRM1 static void __fd_rem(int fd) - */ - REGPRM1 static void __fd_clo(int fd) - { -- if (fd_list[fd].e & FD_EV_RW_SL) -- release_spec_entry(fd); -+ release_spec_entry(fd); - fd_list[fd].e &= ~(FD_EV_MASK); - } - -@@ -325,7 +324,7 @@ REGPRM2 static void _do_poll(struct poller *p, struct timeval *exp) - fdtab[fd].ev &= FD_POLL_STICKY; - if ((eo & FD_EV_MASK_R) == FD_EV_SPEC_R) { - /* The owner is interested in reading from this FD */ -- if (fdtab[fd].state != FD_STCLOSE && fdtab[fd].state != FD_STERROR) { -+ if (fdtab[fd].state != FD_STERROR) { - /* Pretend there is something to read */ - fdtab[fd].ev |= FD_POLL_IN; - if (!fdtab[fd].cb[DIR_RD].f(fd)) -@@ -341,7 +340,7 @@ REGPRM2 static void _do_poll(struct poller *p, struct timeval *exp) - - if ((eo & FD_EV_MASK_W) == FD_EV_SPEC_W) { - /* The owner is interested in writing to this FD */ -- if (fdtab[fd].state != FD_STCLOSE && fdtab[fd].state != FD_STERROR) { -+ if (fdtab[fd].state != FD_STERROR) { - /* Pretend there is something to write */ - fdtab[fd].ev |= FD_POLL_OUT; - if (!fdtab[fd].cb[DIR_WR].f(fd)) diff -u haproxy-1.3.15.2/debian/patches/series haproxy-1.3.15.2/debian/patches/series --- haproxy-1.3.15.2/debian/patches/series +++ haproxy-1.3.15.2/debian/patches/series @@ -1,10 +1,31 @@ -use_backend-consider-unless.patch -segfault-url_param+check_post.patch -server-timeout.patch -closed-fd-remove.patch -connection-slot-during-retry.patch -srv_dynamic_maxconn.patch -do-not-pause-backends-on-reload.patch -acl-in-default.patch -cookie-capture-check.patch -dead-servers-queue.patch +0001-BUG-disable-buffer-read-timeout-when-reading-stats.patch +0004-BUG-use_backend-would-not-correctly-consider-unless.patch +0006-BUG-fix-segfault-with-url_param-check_post.patch +0007-BUG-server-timeout-was-not-considered-in-some-circum.patch +0008-BUG-ev_sepoll-closed-file-descriptors-could-persist-.patch +0009-BUG-maintain_proxies-must-not-disable-backends.patch +0013-BUG-do-not-release-the-connection-slot-during-a-retr.patch +0014-BUG-dynamic-connection-throttling-could-return-a-max.patch +0016-BUG-do-not-try-to-pause-backends-during-reload.patch +0017-BUG-ensure-that-listeners-from-disabled-proxies-are-.patch +0018-BUG-acl-related-keywords-are-not-allowed-in-defaults.patch +0021-BUG-cookie-capture-is-declared-in-the-frontend-but-c.patch +0024-BUG-critical-errors-should-be-reported-even-in-daemo.patch +0025-BUG-do-not-dequeue-requests-on-a-dead-server.patch +0026-BUG-do-not-dequeue-the-backend-s-pending-connections.patch +0028-BUG-Fix-listen-more-of-2-couples-ip-port.patch +0030-CRITICAL-fix-server-state-tracking-it-was-O-n-instea.patch +0031-BUG-option-transparent-is-for-backend-not-frontend.patch +0032-BUG-we-must-not-exit-if-protocol-binding-only-return.patch +0033-BUG-inform-the-user-when-root-is-expected-but-not-se.patch +0035-BUG-the-source-keyword-must-first-clear-optional-set.patch +0036-BUG-global.tune.maxaccept-must-be-limited-even-in-mo.patch +0037-BUG-typo-in-timeout-error-reporting-report-res-and-n.patch +0042-BUG-server-check-intervals-must-not-be-null.patch +0043-BUG-check-for-global.maxconn-before-doing-accept.patch +0047-BUG-stats-total-and-lbtot-are-unsigned.patch +0049-MEDIUM-ensure-we-don-t-recursively-call-pool_gc2.patch +0050-CRITICAL-uninitialized-response-field-can-sometimes-.patch +0052-BUG-O-1-pollers-should-check-their-FD-before-closing.patch +0057-BUG-ensure-that-we-correctly-re-start-old-process-in.patch +0059-BUG-stream_sock-don-t-stop-reading-when-the-poller-r.patch reverted: --- haproxy-1.3.15.2/debian/patches/segfault-url_param+check_post.patch +++ haproxy-1.3.15.2.orig/debian/patches/segfault-url_param+check_post.patch @@ -1,80 +0,0 @@ -commit 3449d158ad4a44a7743854a9f754d4bd775007da -Author: Willy Tarreau -Date: Mon Aug 11 00:21:56 2008 +0200 - - [BUG] fix segfault with url_param + check_post - - If an HTTP/0.9-like POST request is sent to haproxy while - configured with url_param + check_post, it will crash. The - reason is that the total buffer length was computed based - on req->total (which equals the number of bytes read) and - not req->l (number of bytes in the buffer), thus leading - to wrong size calculations when calling memchr(). - - The affected code does not look like it could have been - exploited to run arbitrary code, only reads were performed - at wrong locations. - (cherry picked from commit fb0528bd56063e9800c7dd6fbd96b3c5c6a687f2) - -diff --git a/src/backend.c b/src/backend.c -index cdd8c90..26e6495 100644 ---- a/src/backend.c -+++ b/src/backend.c -@@ -1201,7 +1201,7 @@ struct server *get_server_ph_post(struct session *s) - return NULL; - - body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1; -- len = req->total - body; -+ len = req->l - body; - params = req->data + body; - - if ( len == 0 ) -diff --git a/src/proto_http.c b/src/proto_http.c -index f80129c..425fde6 100644 ---- a/src/proto_http.c -+++ b/src/proto_http.c -@@ -2077,7 +2077,7 @@ int process_cli(struct session *t) - */ - if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) && - t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL && -- t->be->url_param_post_limit != 0 && req->total < BUFSIZE && -+ t->be->url_param_post_limit != 0 && req->l < BUFSIZE && - memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) { - /* are there enough bytes here? total == l || r || rlim ? - * len is unsigned, but eoh is int, -@@ -2085,7 +2085,7 @@ int process_cli(struct session *t) - * eoh is the first empty line of the header - */ - /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */ -- unsigned long len = req->total - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1); -+ unsigned long len = req->l - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1); - - /* If we have HTTP/1.1 and Expect: 100-continue, then abort. - * We can't assume responsibility for the server's decision, -@@ -3615,7 +3615,7 @@ int process_srv(struct session *t) - */ - struct http_msg * msg = &t->txn.req; - unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1; -- unsigned long len = req->total - body; -+ unsigned long len = req->l - body; - long long limit = t->be->url_param_post_limit; - struct hdr_ctx ctx; - ctx.idx = 0; -@@ -3623,7 +3623,7 @@ int process_srv(struct session *t) - http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx); - if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) { - unsigned int chunk = 0; -- while ( body < req->total && !HTTP_IS_CRLF(msg->sol[body])) { -+ while ( body < req->l && !HTTP_IS_CRLF(msg->sol[body])) { - char c = msg->sol[body]; - if (ishex(c)) { - unsigned int hex = toupper(c) - '0'; -@@ -3635,7 +3635,7 @@ int process_srv(struct session *t) - body++; - len--; - } -- if ( body == req->total ) -+ if ( body + 2 >= req->l ) - return 0; /* end of buffer? data missing! */ - - if ( memcmp(msg->sol+body, "\r\n", 2) != 0 ) only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0030-CRITICAL-fix-server-state-tracking-it-was-O-n-instea.patch +++ haproxy-1.3.15.2/debian/patches/0030-CRITICAL-fix-server-state-tracking-it-was-O-n-instea.patch @@ -0,0 +1,58 @@ +From 121c80111c37ff291d04fde300d035dff313af57 Mon Sep 17 00:00:00 2001 +From: Krzysztof Piotr Oledzki +Date: Fri, 30 Jan 2009 00:52:49 +0100 +Subject: [PATCH 30/62] [CRITICAL] fix server state tracking: it was O(n!) instead of O(n) + +Using the wrong operator (&& instead of &) causes DOWN->UP +transition to take longer than it should and to produce a lot of +redundant logs. With typical "track" usage (1-6 tracking servers) it +shouldn't make a big difference but for heavily tracked servers +this bug leads to hang with 100% CPU usage and extremely big +log spam. +--- + src/checks.c | 8 ++++---- + 1 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/checks.c b/src/checks.c +index 0b8756b..82de260 100644 +--- a/src/checks.c ++++ b/src/checks.c +@@ -164,7 +164,7 @@ static void set_server_down(struct server *s) + + s->down_trans++; + +- if (s->state && SRV_CHECKED) ++ if (s->state & SRV_CHECKED) + for(srv = s->tracknext; srv; srv = srv->tracknext) + set_server_down(srv); + } +@@ -229,7 +229,7 @@ static void set_server_up(struct server *s) { + Warning("%s", trash); + send_log(s->proxy, LOG_NOTICE, "%s", trash); + +- if (s->state && SRV_CHECKED) ++ if (s->state & SRV_CHECKED) + for(srv = s->tracknext; srv; srv = srv->tracknext) + set_server_up(srv); + } +@@ -280,7 +280,7 @@ static void set_server_disabled(struct server *s) { + if (!s->proxy->srv_bck && !s->proxy->srv_act) + set_backend_down(s->proxy); + +- if (s->state && SRV_CHECKED) ++ if (s->state & SRV_CHECKED) + for(srv = s->tracknext; srv; srv = srv->tracknext) + set_server_disabled(srv); + } +@@ -320,7 +320,7 @@ static void set_server_enabled(struct server *s) { + Warning("%s", trash); + send_log(s->proxy, LOG_NOTICE, "%s", trash); + +- if (s->state && SRV_CHECKED) ++ if (s->state & SRV_CHECKED) + for(srv = s->tracknext; srv; srv = srv->tracknext) + set_server_enabled(srv); + } +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0028-BUG-Fix-listen-more-of-2-couples-ip-port.patch +++ haproxy-1.3.15.2/debian/patches/0028-BUG-Fix-listen-more-of-2-couples-ip-port.patch @@ -0,0 +1,31 @@ +From 1d62e33b0108a1da634c1936605235635df3081d Mon Sep 17 00:00:00 2001 +From: Krzysztof Piotr Oledzki +Date: Tue, 27 Jan 2009 16:57:08 +0100 +Subject: [PATCH 28/62] [BUG] Fix listen & more of 2 couples : + +Fix "listen www-mutualise 80.248.x.y1:80,80.248.x.y2:80,80.248.x.y3:80": + +[ALERT] 309/161509 (15450) : Invalid server address: '80.248.x.y1:80,80.248.x.y2' +[ALERT] 309/161509 (15450) : Error reading configuration file : /etc/haproxy/haproxy.cfg + +Bug reported by Laurent Dolosor. +--- + src/cfgparse.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index 4da1b67..64a001e 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -144,7 +144,7 @@ static struct listener *str2listener(char *str, struct listener *tail) + + str = next; + /* 1) look for the end of the first address */ +- if ((next = strrchr(str, ',')) != NULL) { ++ if ((next = strchr(str, ',')) != NULL) { + *next++ = 0; + } + +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0031-BUG-option-transparent-is-for-backend-not-frontend.patch +++ haproxy-1.3.15.2/debian/patches/0031-BUG-option-transparent-is-for-backend-not-frontend.patch @@ -0,0 +1,123 @@ +From c34da593ed579f373d1176fb510a1e59c474ba6d Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 23 Dec 2008 23:13:55 +0100 +Subject: [PATCH 31/62] [BUG] "option transparent" is for backend, not frontend ! + +"option transparent" was set and checked on frontends only while it +is purely a backend thing as it replaces the "balance" mode. For this +reason, it did only work in "listen" sections. This change will then +not affect the rare users of this option. +(cherry picked from commit 4b1f85912c5dfd7e53dfa31d3e9dd3113747c702) +--- + doc/configuration.txt | 14 ++++---------- + src/backend.c | 6 +++--- + src/cfgparse.c | 2 +- + 3 files changed, 8 insertions(+), 14 deletions(-) + +diff --git a/doc/configuration.txt b/doc/configuration.txt +index 725d9fa..21f5439 100644 +--- a/doc/configuration.txt ++++ b/doc/configuration.txt +@@ -567,7 +567,7 @@ option ssl-hello-chk X - X X + option tcpka X X X X + option tcplog X X X X + [no] option tcpsplice X X X X +-[no] option transparent X X X - ++[no] option transparent X - X X + redisp X - X X (deprecated) + redispatch X - X X (deprecated) + reqadd - X X X +@@ -613,7 +613,7 @@ timeout queue X - X X + timeout server X - X X + timeout srvtimeout X - X X (deprecated) + timeout tarpit X X X X +-transparent X X X - (deprecated) ++transparent X - X X (deprecated) + use_backend - X X - + ----------------------+----------+----------+---------+--------- + keyword defaults frontend listen backend +@@ -2271,7 +2271,7 @@ option transparent + no option transparent + Enable client-side transparent proxying + May be used in sections : defaults | frontend | listen | backend +- yes | yes | yes | no ++ yes | no | yes | yes + Arguments : none + + This option was introduced in order to provide layer 7 persistence to layer 3 +@@ -2286,9 +2286,6 @@ no option transparent + Note that contrary to a common belief, this option does NOT make HAProxy + present the client's IP to the server when establishing the connection. + +- Use of this option is really discouraged, and since no really valid use of it +- has been reported for years, it will probably be removed in future versions. +- + See also: the "usersrc" argument of the "source" keyword, and the + "transparent" option of the "bind" keyword. + +@@ -3377,7 +3374,7 @@ timeout tarpit + transparent (deprecated) + Enable client-side transparent proxying + May be used in sections : defaults | frontend | listen | backend +- yes | yes | yes | no ++ yes | no | yes | yes + Arguments : none + + This keyword was introduced in order to provide layer 7 persistence to layer +@@ -3394,9 +3391,6 @@ transparent (deprecated) + Note that contrary to a common belief, this option does NOT make HAProxy + present the client's IP to the server when establishing the connection. + +- Use of this option is really discouraged, and since no really valid use of it +- has been reported for years, it will probably be removed in future versions. +- + See also: "option transparent" + + +diff --git a/src/backend.c b/src/backend.c +index 26e6495..be1f136 100644 +--- a/src/backend.c ++++ b/src/backend.c +@@ -1417,7 +1417,7 @@ int assign_server(struct session *s) + } + } + else if (!*(int *)&s->be->dispatch_addr.sin_addr && +- !(s->fe->options & PR_O_TRANSP)) { ++ !(s->be->options & PR_O_TRANSP)) { + err = SRV_STATUS_NOSRV; + goto out; + } +@@ -1472,7 +1472,7 @@ int assign_server_address(struct session *s) + /* if this server remaps proxied ports, we'll use + * the port the client connected to with an offset. */ + if (s->srv->state & SRV_MAPPORTS) { +- if (!(s->fe->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET)) ++ if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET)) + get_frt_addr(s); + if (s->frt_addr.ss_family == AF_INET) { + s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + +@@ -1487,7 +1487,7 @@ int assign_server_address(struct session *s) + /* connect to the defined dispatch addr */ + s->srv_addr = s->be->dispatch_addr; + } +- else if (s->fe->options & PR_O_TRANSP) { ++ else if (s->be->options & PR_O_TRANSP) { + /* in transparent mode, use the original dest addr if no dispatch specified */ + if (!(s->flags & SN_FRT_ADDR_SET)) + get_frt_addr(s); +diff --git a/src/cfgparse.c b/src/cfgparse.c +index c7c7383..d09d6da 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -109,7 +109,7 @@ static const struct { + { "tcpsplice", PR_O_TCPSPLICE, PR_CAP_BE|PR_CAP_FE, LSTCHK_TCPSPLICE|LSTCHK_NETADM }, + #endif + #ifdef TPROXY +- { "transparent", PR_O_TRANSP, PR_CAP_FE, 0 }, ++ { "transparent", PR_O_TRANSP, PR_CAP_BE, 0 }, + #endif + + { NULL, 0, 0, 0 } +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0047-BUG-stats-total-and-lbtot-are-unsigned.patch +++ haproxy-1.3.15.2/debian/patches/0047-BUG-stats-total-and-lbtot-are-unsigned.patch @@ -0,0 +1,63 @@ +From 1e8e543c67118c408015698782f4691d9faf96d1 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 7 Apr 2009 13:27:40 +0200 +Subject: [PATCH 47/62] [BUG] stats: total and lbtot are unsigned + +Some big users are seeing negative numbers in the CSV stats. This patch +needs to be backported to 1.3.15 and extended to the HTML part. +--- + src/dumpstats.c | 10 +++++----- + 1 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/dumpstats.c b/src/dumpstats.c +index 894c248..b5ecddc 100644 +--- a/src/dumpstats.c ++++ b/src/dumpstats.c +@@ -699,7 +699,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) + /* pxid, name, queue cur, queue max, */ + "%s,FRONTEND,,," + /* sessions : current, max, limit, total */ +- "%d,%d,%d,%d," ++ "%d,%d,%d,%u," + /* bytes : in, out */ + "%lld,%lld," + /* denied: req, resp */ +@@ -871,7 +871,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) + /* queue : current, max */ + "%d,%d," + /* sessions : current, max, limit, total */ +- "%d,%d,%s,%d," ++ "%d,%d,%s,%u," + /* bytes : in, out */ + "%lld,%lld," + /* denied: req, resp */ +@@ -930,7 +930,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) + } + + /* sessions: lbtot */ +- chunk_printf(&msg, sizeof(trash), ",%d,", sv->cum_lbconn); ++ chunk_printf(&msg, sizeof(trash), ",%u,", sv->cum_lbconn); + + /* tracked */ + if (sv->tracked) +@@ -1004,7 +1004,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) + /* queue : current, max */ + "%d,%d," + /* sessions : current, max, limit, total */ +- "%d,%d,%d,%d," ++ "%d,%d,%d,%u," + /* bytes : in, out */ + "%lld,%lld," + /* denied: req, resp */ +@@ -1022,7 +1022,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) + /* rest of backend: nothing, down transitions, last change, total downtime */ + ",%d,%d,%d,," + /* pid, iid, sid, throttle, lbtot, tracked, type */ +- "%d,%d,0,,%d,,%d," ++ "%d,%d,0,,%u,,%d," + "\n", + px->id, + px->nbpend /* or px->totpend ? */, px->nbpend_max, +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0008-BUG-ev_sepoll-closed-file-descriptors-could-persist-.patch +++ haproxy-1.3.15.2/debian/patches/0008-BUG-ev_sepoll-closed-file-descriptors-could-persist-.patch @@ -0,0 +1,51 @@ +From 116f4105d4fc6fbd8f2d0a139f691973332176de Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sat, 16 Aug 2008 16:06:02 +0200 +Subject: [PATCH 08/62] [BUG] ev_sepoll: closed file descriptors could persist in the spec list + +If __fd_clo() was called on a file descriptor which was previously +disabled, it was not removed from the spec list. This apparently +could not happen on previous code because the TCP states prevented +this, but now it happens regularly. The effects are spec entries +stuck populated, leading to busy loops. + +(cherry picked from commit 7a52a5c4680477272b2f34eaf5896b85746e6fd6) +--- + src/ev_sepoll.c | 7 +++---- + 1 files changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c +index 800ac0b..db35423 100644 +--- a/src/ev_sepoll.c ++++ b/src/ev_sepoll.c +@@ -279,8 +279,7 @@ REGPRM1 static void __fd_rem(int fd) + */ + REGPRM1 static void __fd_clo(int fd) + { +- if (fd_list[fd].e & FD_EV_RW_SL) +- release_spec_entry(fd); ++ release_spec_entry(fd); + fd_list[fd].e &= ~(FD_EV_MASK); + } + +@@ -325,7 +324,7 @@ REGPRM2 static void _do_poll(struct poller *p, struct timeval *exp) + fdtab[fd].ev &= FD_POLL_STICKY; + if ((eo & FD_EV_MASK_R) == FD_EV_SPEC_R) { + /* The owner is interested in reading from this FD */ +- if (fdtab[fd].state != FD_STCLOSE && fdtab[fd].state != FD_STERROR) { ++ if (fdtab[fd].state != FD_STERROR) { + /* Pretend there is something to read */ + fdtab[fd].ev |= FD_POLL_IN; + if (!fdtab[fd].cb[DIR_RD].f(fd)) +@@ -341,7 +340,7 @@ REGPRM2 static void _do_poll(struct poller *p, struct timeval *exp) + + if ((eo & FD_EV_MASK_W) == FD_EV_SPEC_W) { + /* The owner is interested in writing to this FD */ +- if (fdtab[fd].state != FD_STCLOSE && fdtab[fd].state != FD_STERROR) { ++ if (fdtab[fd].state != FD_STERROR) { + /* Pretend there is something to write */ + fdtab[fd].ev |= FD_POLL_OUT; + if (!fdtab[fd].cb[DIR_WR].f(fd)) +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0036-BUG-global.tune.maxaccept-must-be-limited-even-in-mo.patch +++ haproxy-1.3.15.2/debian/patches/0036-BUG-global.tune.maxaccept-must-be-limited-even-in-mo.patch @@ -0,0 +1,63 @@ +From d80d63b6df4fe2d8711a83f88c51a7e3a0e139ed Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 1 Mar 2009 08:35:41 +0100 +Subject: [PATCH 36/62] [BUG] global.tune.maxaccept must be limited even in mono-process mode + +On overloaded systems, it sometimes happens that hundreds or thousands +of incoming connections are queued in the system's backlog, and all get +dequeued at once. The problem is that when haproxy processes them and +does not apply any limit, this can take some time and the internal date +does not progress, resulting in wrong timer measures for all sessions. + +The most common effect of this is that all of these sessions report a +large request time (around several hundreds of ms) which is in fact +caused by the time spent accepting other connections. This might happen +on shared systems when the machine swaps. + +For this reason, we finally apply a reasonable limit even in mono-process +mode. Accepting 100 connections at once is fast enough for extreme cases +and will not cause that much of a trouble when the system is saturated. +(cherry picked from commit f49d1df25cf794b8801d919fda20266d90981c78) +--- + doc/configuration.txt | 4 ++-- + src/haproxy.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/doc/configuration.txt b/doc/configuration.txt +index 52ef12c..72fc387 100644 +--- a/doc/configuration.txt ++++ b/doc/configuration.txt +@@ -229,10 +229,10 @@ tune.maxaccept + Sets the maximum number of consecutive accepts that a process may perform on + a single wake up. High values give higher priority to high connection rates, + while lower values give higher priority to already established connections. +- This value is unlimited by default in single process mode. However, in ++ This value is limited to 100 by default in single process mode. However, in + multi-process mode (nbproc > 1), it defaults to 8 so that when one process + wakes up, it does not take all incoming connections for itself and leaves a +- part of them to other processes. Setting this value to zero or less disables ++ part of them to other processes. Setting this value to -1 completely disables + the limitation. It should normally not be needed to tweak this value. + + tune.maxpollevents +diff --git a/src/haproxy.c b/src/haproxy.c +index 39b8918..b53608c 100644 +--- a/src/haproxy.c ++++ b/src/haproxy.c +@@ -562,11 +562,11 @@ void init(int argc, char **argv) + if (global.tune.maxpollevents <= 0) + global.tune.maxpollevents = MAX_POLL_EVENTS; + +- if (global.tune.maxaccept <= 0) { ++ if (global.tune.maxaccept == 0) { + if (global.nbproc > 1) + global.tune.maxaccept = 8; /* leave some conns to other processes */ + else +- global.tune.maxaccept = -1; /* accept all incoming conns */ ++ global.tune.maxaccept = 100; /* accept many incoming conns at once */ + } + + if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) { +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0050-CRITICAL-uninitialized-response-field-can-sometimes-.patch +++ haproxy-1.3.15.2/debian/patches/0050-CRITICAL-uninitialized-response-field-can-sometimes-.patch @@ -0,0 +1,39 @@ +From c0e4eb7d1dc3636757232ce730cbc9a8f6ac34d8 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Mon, 27 Apr 2009 08:11:33 +0200 +Subject: [PATCH 50/62] [CRITICAL] uninitialized response field can sometimes cause crashes + +[cherry-picked from commit 79e998919660b2ec6d5dc11be9d820c5c1965460] + +The response message in the transaction structure was not properly +initialised at session initialisation. In theory it cannot cause any +trouble since the affected field os expected to always remain NULL. +However, in some circumstances, such as building on 64-bit platforms +with certain options, the struct session can be exactly 1024 bytes, +the same size of the requri field, so the pools are merged and the +uninitialised field may contain non-null data, causing crashes if +an invalid response is encountered and archived. + +The fix simply consists in correctly initialising the missing fields. +This bug cannot affect architectures where the session pool is not +shared (32-bit architectures), but this is only by pure luck. +--- + src/client.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/src/client.c b/src/client.c +index 9498b13..8146190 100644 +--- a/src/client.c ++++ b/src/client.c +@@ -238,6 +238,8 @@ int event_accept(int fd) { + txn->rsp.msg_state = HTTP_MSG_RPBEFORE; /* at the very beginning of the response */ + txn->req.sol = txn->req.eol = NULL; + txn->req.som = txn->req.eoh = 0; /* relative to the buffer */ ++ txn->rsp.sol = txn->rsp.eol = NULL; ++ txn->rsp.som = txn->rsp.eoh = 0; /* relative to the buffer */ + txn->auth_hdr.len = -1; + + if (p->nb_req_cap > 0) { +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0043-BUG-check-for-global.maxconn-before-doing-accept.patch +++ haproxy-1.3.15.2/debian/patches/0043-BUG-check-for-global.maxconn-before-doing-accept.patch @@ -0,0 +1,46 @@ +From dea567ef66e1f0d6eafe29ff8a9c68b54ff40c90 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sat, 21 Mar 2009 22:43:12 +0100 +Subject: [PATCH 43/62] [BUG] check for global.maxconn before doing accept() + +[cherry-picked from commit b00f9c456c0eadd26abbbf4bb0a3276da9f1844e] + +If the accept() is done before checking for global.maxconn, we can +accept too many connections and encounter a lack of file descriptors +when trying to connect to the server. This is the cause of the +"cannot get a server socket" message encountered in debug mode +during injections with low timeouts. +--- + src/client.c | 2 +- + src/proto_uxst.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/client.c b/src/client.c +index 1dd318f..9498b13 100644 +--- a/src/client.c ++++ b/src/client.c +@@ -76,7 +76,7 @@ int event_accept(int fd) { + int cfd; + int max_accept = global.tune.maxaccept; + +- while (p->feconn < p->maxconn && max_accept--) { ++ while (p->feconn < p->maxconn && actconn < global.maxconn && max_accept--) { + struct sockaddr_storage addr; + socklen_t laddr = sizeof(addr); + +diff --git a/src/proto_uxst.c b/src/proto_uxst.c +index b708689..76854f2 100644 +--- a/src/proto_uxst.c ++++ b/src/proto_uxst.c +@@ -374,7 +374,7 @@ int uxst_event_accept(int fd) { + else + max_accept = -1; + +- while (max_accept--) { ++ while (actconn < global.maxconn && max_accept--) { + struct sockaddr_storage addr; + socklen_t laddr = sizeof(addr); + +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0024-BUG-critical-errors-should-be-reported-even-in-daemo.patch +++ haproxy-1.3.15.2/debian/patches/0024-BUG-critical-errors-should-be-reported-even-in-daemo.patch @@ -0,0 +1,47 @@ +From 304d6fb00fe32fca1bd932a301d4afb7d54c92bc Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 16 Nov 2008 07:40:34 +0100 +Subject: [PATCH 24/62] [BUG] critical errors should be reported even in daemon mode + +Josh Goebel reported that haproxy silently dies when it fails to +chroot. In fact, it does so when in daemon mode, because daemon +mode has been disabling output for ages. + +Since the code has been reworked, this could have been changed +because there is no reason for this anymore, hence this patch. +--- + src/haproxy.c | 8 ++------ + 1 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/src/haproxy.c b/src/haproxy.c +index 50b013b..3eedfce 100644 +--- a/src/haproxy.c ++++ b/src/haproxy.c +@@ -895,11 +895,6 @@ int main(int argc, char **argv) + signal(SIGTTOU, sig_pause); + signal(SIGTTIN, sig_listen); + +- if (global.mode & MODE_DAEMON) { +- global.mode &= ~MODE_VERBOSE; +- global.mode |= MODE_QUIET; +- } +- + /* MODE_QUIET can inhibit alerts and warnings below this line */ + + global.mode &= ~MODE_STARTING; +@@ -1061,10 +1056,11 @@ int main(int argc, char **argv) + * it would have already be done, and 0-2 would have been affected to listening + * sockets + */ +- if (!(global.mode & MODE_QUIET)) { ++ if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) { + /* detach from the tty */ + fclose(stdin); fclose(stdout); fclose(stderr); + close(0); close(1); close(2); /* close all fd's */ ++ global.mode &= ~MODE_VERBOSE; + global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */ + } + pid = getpid(); /* update child's pid */ +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0014-BUG-dynamic-connection-throttling-could-return-a-max.patch +++ haproxy-1.3.15.2/debian/patches/0014-BUG-dynamic-connection-throttling-could-return-a-max.patch @@ -0,0 +1,33 @@ +From 819970098f134453c0934047b3bd3440b0996b55 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 14 Sep 2008 17:43:27 +0200 +Subject: [PATCH 14/62] [BUG] dynamic connection throttling could return a max of zero conns + +srv_dynamic_maxconn() is clearly documented as returning at least 1 +possible connection under throttling. But the computation was wrong, +the minimum 1 was divided and got lost in case of very low maxconns. + +Apply the MAX(1, max) before returning the result in order to ensure +that a newly appeared server will get some traffic. +--- + src/queue.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/queue.c b/src/queue.c +index 178f187..905994a 100644 +--- a/src/queue.c ++++ b/src/queue.c +@@ -55,8 +55,8 @@ unsigned int srv_dynamic_maxconn(const struct server *s) + now.tv_sec < s->last_change + s->slowstart && + now.tv_sec >= s->last_change) { + unsigned int ratio; +- ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / s->slowstart); +- max = max * ratio / 100; ++ ratio = 100 * (now.tv_sec - s->last_change) / s->slowstart; ++ max = MAX(1, max * ratio / 100); + } + return max; + } +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0004-BUG-use_backend-would-not-correctly-consider-unless.patch +++ haproxy-1.3.15.2/debian/patches/0004-BUG-use_backend-would-not-correctly-consider-unless.patch @@ -0,0 +1,28 @@ +From e05484f3ec2f2824c88d3a0c68a415111addadb1 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Wed, 9 Jul 2008 11:23:31 +0200 +Subject: [PATCH 04/62] [BUG] use_backend would not correctly consider "unless" + +A copy-paste typo made use_backend not correctly consider the "unless" +case, depending on the previous "block" rule. +(cherry picked from commit a8cfa34a9c011cecfaedfaf7d91de3e5f7f004a0) +--- + src/proto_http.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/src/proto_http.c b/src/proto_http.c +index e36f4b0..f80129c 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -1925,7 +1925,7 @@ int process_cli(struct session *t) + int ret; + + ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ); +- if (cond->pol == ACL_COND_UNLESS) ++ if (rule->cond->pol == ACL_COND_UNLESS) + ret = !ret; + + if (ret) { +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0013-BUG-do-not-release-the-connection-slot-during-a-retr.patch +++ haproxy-1.3.15.2/debian/patches/0013-BUG-do-not-release-the-connection-slot-during-a-retr.patch @@ -0,0 +1,37 @@ +From 8262d8bd7fdb262c980bd70cb2931e51df07513f Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 14 Sep 2008 17:40:09 +0200 +Subject: [PATCH 13/62] [BUG] do not release the connection slot during a retry + +A bug was introduced during last queue management fix. If a server +connection fails, the allocated connection slot is released, but it +will be needed again after the turn-around. This also causes more +connections than expected to go to the server because it appears to +have less connections than real. + +Many thanks to Rupert Fiasco, Mark Imbriaco, Cody Fauser, Brian +Gupta and Alexander Staubo for promptly providing configuration +and diagnosis elements to help reproduce this problem easily. +--- + src/proto_http.c | 4 +--- + 1 files changed, 1 insertions(+), 3 deletions(-) + +diff --git a/src/proto_http.c b/src/proto_http.c +index 425fde6..7500798 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -2686,10 +2686,8 @@ int process_srv(struct session *t) + } + else { + fd_delete(t->srv_fd); +- if (t->srv) { ++ if (t->srv) + t->srv->cur_sess--; +- sess_change_server(t, NULL); +- } + + if (!(req->flags & BF_WRITE_STATUS)) + conn_err = SN_ERR_SRVTO; // it was a connect timeout. +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0021-BUG-cookie-capture-is-declared-in-the-frontend-but-c.patch +++ haproxy-1.3.15.2/debian/patches/0021-BUG-cookie-capture-is-declared-in-the-frontend-but-c.patch @@ -0,0 +1,77 @@ +From bfca9e51b77b856593a3c4a3215a8e0397e7cdba Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Fri, 17 Oct 2008 12:01:58 +0200 +Subject: [PATCH 21/62] [BUG] cookie capture is declared in the frontend but checked on the backend + +Cookie capture would only work by pure luck on the request but did +never work on responses since only the backend was checked. The fix +consists in always checking frontend for cookie captures. +(cherry picked from commit a83c5ba9315a7c47cda2698280b7e49a9d3eb374) +--- + src/proto_http.c | 20 +++++++++++--------- + 1 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/src/proto_http.c b/src/proto_http.c +index 7500798..0a59fe1 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -2009,7 +2009,7 @@ int process_cli(struct session *t) + * the fields will stay coherent and the URI will not move. + * This should only be performed in the backend. + */ +- if ((t->be->cookie_name || t->be->appsession_name || t->be->capture_name) ++ if ((t->be->cookie_name || t->be->appsession_name || t->fe->capture_name) + && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) + manage_client_side_cookies(t, req); + +@@ -3193,7 +3193,7 @@ int process_srv(struct session *t) + /* + * 4: check for server cookie. + */ +- if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name ++ if (t->be->cookie_name || t->be->appsession_name || t->fe->capture_name + || (t->be->options & PR_O_CHK_CACHE)) + manage_server_side_cookies(t, rep); + +@@ -4600,10 +4600,12 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr) + txn->flags |= TX_SCK_ANY; + + +- /* maybe we only wanted to see if there was a set-cookie */ ++ /* maybe we only wanted to see if there was a set-cookie. Note that ++ * the cookie capture is declared on the frontend. ++ */ + if (t->be->cookie_name == NULL && + t->be->appsession_name == NULL && +- t->be->capture_name == NULL) ++ t->fe->capture_name == NULL) + return; + + p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */ +@@ -4635,18 +4637,18 @@ void manage_server_side_cookies(struct session *t, struct buffer *rtr) + */ + + /* first, let's see if we want to capture it */ +- if (t->be->capture_name != NULL && ++ if (t->fe->capture_name != NULL && + txn->srv_cookie == NULL && +- (p4 - p1 >= t->be->capture_namelen) && +- memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) { ++ (p4 - p1 >= t->fe->capture_namelen) && ++ memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) { + int log_len = p4 - p1; + + if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) { + Alert("HTTP logging : out of memory.\n"); + } + +- if (log_len > t->be->capture_len) +- log_len = t->be->capture_len; ++ if (log_len > t->fe->capture_len) ++ log_len = t->fe->capture_len; + memcpy(txn->srv_cookie, p1, log_len); + txn->srv_cookie[log_len] = 0; + } +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0032-BUG-we-must-not-exit-if-protocol-binding-only-return.patch +++ haproxy-1.3.15.2/debian/patches/0032-BUG-we-must-not-exit-if-protocol-binding-only-return.patch @@ -0,0 +1,37 @@ +From 035514abcf6139ff7da2b54f89c17117b6ddf57f Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Wed, 4 Feb 2009 17:05:23 +0100 +Subject: [PATCH 32/62] [BUG] we must not exit if protocol binding only returns a warning + +Right now, protocol binding cannot return a warning, but when this +will happen, we must not exit but just print the warning. +(cherry picked from commit 0a3b9d90d3570cb618c7008cd1d7348d48a3868c) +--- + src/haproxy.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/haproxy.c b/src/haproxy.c +index 3eedfce..6eca3bf 100644 +--- a/src/haproxy.c ++++ b/src/haproxy.c +@@ -870,7 +870,7 @@ int main(int argc, char **argv) + } + + /* Note: start_proxies() sends an alert when it fails. */ +- if (err != ERR_NONE) { ++ if ((err & ~ERR_WARN) != ERR_NONE) { + if (retry != MAX_START_RETRIES && nb_oldpids) + tell_old_pids(SIGTTIN); + exit(1); +@@ -883,7 +883,7 @@ int main(int argc, char **argv) + exit(1); + } + +- if (protocol_bind_all() != ERR_NONE) { ++ if ((protocol_bind_all() & ~ERR_WARN) != ERR_NONE) { + Alert("[%s.main()] Some protocols failed to start their listeners! Exiting.\n", argv[0]); + protocol_unbind_all(); /* cleanup everything we can */ + if (nb_oldpids) +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0059-BUG-stream_sock-don-t-stop-reading-when-the-poller-r.patch +++ haproxy-1.3.15.2/debian/patches/0059-BUG-stream_sock-don-t-stop-reading-when-the-poller-r.patch @@ -0,0 +1,61 @@ +From ab0683580ba310130c673000f07b6965f472d4e9 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 14 Jul 2009 19:55:05 +0200 +Subject: [PATCH 59/62] [BUG] stream_sock: don't stop reading when the poller reports an error + +As reported by Jean-Baptiste Quenot and Robbie Aelter, sometimes a +backend server error is converted to a 502 error if the backend stops +before reading all the request. The reason is that the remote system +sends a TCP RST packet because there are still unread data pending in +the socket buffer. This RST is translated as a socket error on the +local system, and this error is reported by the poller. + +However, most of the time, it's a write error, but the system is +still able to read the remaining pending data, such as in the trace +below : + +send(7, "GET /aaa HTTP/1.0\r\nUser-Agent: Mo"..., 1123, MSG_DONTWAIT|MSG_NOSIGNAL) = 1123 +epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLIN, {u32=7, u64=7}}) = 0 +epoll_wait(3, {{EPOLLIN|EPOLLERR|EPOLLHUP, {u32=7, u64=7}}}, 8, 1000) = 1 +gettimeofday({1247593958, 643572}, NULL) = 0 +recv(7, "HTTP/1.0 400 Bad request\r\nCache-C"..., 7000, MSG_NOSIGNAL) = 187 +setsockopt(6, SOL_TCP, TCP_NODELAY, [0], 4) = 0 +setsockopt(6, SOL_TCP, TCP_CORK, [1], 4) = 0 +send(6, "HTTP/1.0 400 Bad request\r\nCache-C"..., 187, MSG_DONTWAIT|MSG_NOSIGNAL) = 187 +shutdown(6, 1 /* send */) = 0 + +The recv succeeded while epoll_wait() reported an error. + +Note: This case is very hard to reproduce and requires that the backend +server is reached via the loopback in order to minimise latency and +reduce the risk of sent data being ACKed. +(cherry picked from commit 7154365cc60b124b543db4e98faedc75c0f3a2cb) +--- + src/stream_sock.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/stream_sock.c b/src/stream_sock.c +index 8bfc55b..d128def 100644 +--- a/src/stream_sock.c ++++ b/src/stream_sock.c +@@ -54,7 +54,7 @@ int stream_sock_read(int fd) { + retval = 1; + + /* stop immediately on errors */ +- if (fdtab[fd].state == FD_STERROR || (fdtab[fd].ev & FD_POLL_ERR)) ++ if (fdtab[fd].state == FD_STERROR) + goto out_error; + + /* stop here if we reached the end of data */ +@@ -220,7 +220,7 @@ int stream_sock_write(int fd) { + #endif + + retval = 1; +- if (fdtab[fd].state == FD_STERROR || (fdtab[fd].ev & FD_POLL_ERR)) ++ if (fdtab[fd].state == FD_STERROR) + goto out_error; + + while (1) { +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0049-MEDIUM-ensure-we-don-t-recursively-call-pool_gc2.patch +++ haproxy-1.3.15.2/debian/patches/0049-MEDIUM-ensure-we-don-t-recursively-call-pool_gc2.patch @@ -0,0 +1,50 @@ +From 5a01de1c74b8c1c0c2a0e62e9fb6b432e24c79f9 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 21 Apr 2009 02:17:45 +0200 +Subject: [PATCH 49/62] [MEDIUM] ensure we don't recursively call pool_gc2() + +A race condition exists in the hot reconfiguration code. It is +theorically possible that the second signal is sent during a free() +in the first list, which can cause crashes or freezes (the later +have been observed). Just set up a counter to ensure we do not +recurse. +(cherry picked from commit b7f9d126e269f3b5b7dc05e39fcf207ba86a330c) +--- + src/memory.c | 10 +++++++++- + 1 files changed, 9 insertions(+), 1 deletions(-) + +diff --git a/src/memory.c b/src/memory.c +index 7948bf2..1fd8f44 100644 +--- a/src/memory.c ++++ b/src/memory.c +@@ -120,11 +120,17 @@ void pool_flush2(struct pool_head *pool) + + /* + * This function frees whatever can be freed in all pools, but respecting +- * the minimum thresholds imposed by owners. ++ * the minimum thresholds imposed by owners. It takes care of avoiding ++ * recursion because it may be called from a signal handler. + */ + void pool_gc2() + { ++ static int recurse; + struct pool_head *entry; ++ ++ if (recurse++) ++ goto out; ++ + list_for_each_entry(entry, &pools, list) { + void *temp, *next; + //qfprintf(stderr, "Flushing pool %s\n", entry->name); +@@ -139,6 +145,8 @@ void pool_gc2() + } + entry->free_list = next; + } ++ out: ++ recurse--; + } + + /* +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0009-BUG-maintain_proxies-must-not-disable-backends.patch +++ haproxy-1.3.15.2/debian/patches/0009-BUG-maintain_proxies-must-not-disable-backends.patch @@ -0,0 +1,28 @@ +From 2f9127b4b91de1ac685498e145f29342115bcb71 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sat, 16 Aug 2008 18:41:13 +0200 +Subject: [PATCH 09/62] [BUG] maintain_proxies must not disable backends + +maintain_proxies could disable backends (p->maxconn == 0) which is +wrong (but apparently harmless). Add a check for p->maxconn == 0. +(cherry picked from commit d5382b4aaa099ce5ce2af5828bd4d6dc38e9e8ea) +--- + src/proxy.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/src/proxy.c b/src/proxy.c +index 402fc88..c0e7ab6 100644 +--- a/src/proxy.c ++++ b/src/proxy.c +@@ -314,7 +314,7 @@ void maintain_proxies(struct timeval *next) + /* if there are enough free sessions, we'll activate proxies */ + if (actconn < global.maxconn) { + while (p) { +- if (p->feconn < p->maxconn) { ++ if (!p->maxconn || p->feconn < p->maxconn) { + if (p->state == PR_STIDLE) { + for (l = p->listen; l != NULL; l = l->next) + enable_listener(l); +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0006-BUG-fix-segfault-with-url_param-check_post.patch +++ haproxy-1.3.15.2/debian/patches/0006-BUG-fix-segfault-with-url_param-check_post.patch @@ -0,0 +1,86 @@ +From 3449d158ad4a44a7743854a9f754d4bd775007da Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Mon, 11 Aug 2008 00:21:56 +0200 +Subject: [PATCH 06/62] [BUG] fix segfault with url_param + check_post + +If an HTTP/0.9-like POST request is sent to haproxy while +configured with url_param + check_post, it will crash. The +reason is that the total buffer length was computed based +on req->total (which equals the number of bytes read) and +not req->l (number of bytes in the buffer), thus leading +to wrong size calculations when calling memchr(). + +The affected code does not look like it could have been +exploited to run arbitrary code, only reads were performed +at wrong locations. +(cherry picked from commit fb0528bd56063e9800c7dd6fbd96b3c5c6a687f2) +--- + src/backend.c | 2 +- + src/proto_http.c | 10 +++++----- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/backend.c b/src/backend.c +index cdd8c90..26e6495 100644 +--- a/src/backend.c ++++ b/src/backend.c +@@ -1201,7 +1201,7 @@ struct server *get_server_ph_post(struct session *s) + return NULL; + + body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1; +- len = req->total - body; ++ len = req->l - body; + params = req->data + body; + + if ( len == 0 ) +diff --git a/src/proto_http.c b/src/proto_http.c +index f80129c..425fde6 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -2077,7 +2077,7 @@ int process_cli(struct session *t) + */ + if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) && + t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL && +- t->be->url_param_post_limit != 0 && req->total < BUFSIZE && ++ t->be->url_param_post_limit != 0 && req->l < BUFSIZE && + memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) { + /* are there enough bytes here? total == l || r || rlim ? + * len is unsigned, but eoh is int, +@@ -2085,7 +2085,7 @@ int process_cli(struct session *t) + * eoh is the first empty line of the header + */ + /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */ +- unsigned long len = req->total - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1); ++ unsigned long len = req->l - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1); + + /* If we have HTTP/1.1 and Expect: 100-continue, then abort. + * We can't assume responsibility for the server's decision, +@@ -3615,7 +3615,7 @@ int process_srv(struct session *t) + */ + struct http_msg * msg = &t->txn.req; + unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1; +- unsigned long len = req->total - body; ++ unsigned long len = req->l - body; + long long limit = t->be->url_param_post_limit; + struct hdr_ctx ctx; + ctx.idx = 0; +@@ -3623,7 +3623,7 @@ int process_srv(struct session *t) + http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx); + if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) { + unsigned int chunk = 0; +- while ( body < req->total && !HTTP_IS_CRLF(msg->sol[body])) { ++ while ( body < req->l && !HTTP_IS_CRLF(msg->sol[body])) { + char c = msg->sol[body]; + if (ishex(c)) { + unsigned int hex = toupper(c) - '0'; +@@ -3635,7 +3635,7 @@ int process_srv(struct session *t) + body++; + len--; + } +- if ( body == req->total ) ++ if ( body + 2 >= req->l ) + return 0; /* end of buffer? data missing! */ + + if ( memcmp(msg->sol+body, "\r\n", 2) != 0 ) +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0026-BUG-do-not-dequeue-the-backend-s-pending-connections.patch +++ haproxy-1.3.15.2/debian/patches/0026-BUG-do-not-dequeue-the-backend-s-pending-connections.patch @@ -0,0 +1,94 @@ +From cd485c44807bfcdb4928dd83c1907636b4e1b6f3 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Thu, 4 Dec 2008 09:33:58 +0100 +Subject: [PATCH 26/62] [BUG] do not dequeue the backend's pending connections on a dead server + +Kai Krueger found that previous patch was incomplete, because there is +an unconditionnal call to process_srv_queue() in session_free() which +still causes a dead server to consume pending connections from the +backend. + +This call was made unconditionnal so that we don't leave unserved +connections in the server queue, for instance connections coming +in with "option persist" which can bypass the server status check. +However, the server must not touch the backend's queue if it is down. + +Another fear was that some connections might remain unserved when +the server is using a dynamic maxconn if the number of connections +to the backend is too low. Right now, srv_dynamic_maxconn() ensures +this cannot happen, so the call can remain conditionnal. + +The fix consists in allowing a server to process it own queue whatever +its state, but not to touch the backend's queue if it is down. Its +queue should normally be empty when the server is down because it is +redistributed when the server goes down. The only remaining cases are +precisely the persistent connections with "option persist" set, coming +in after the queue has been redispatched. Those ones must still be +processed when a connection terminates. +--- + include/proto/queue.h | 6 +++--- + src/queue.c | 6 +++++- + src/session.c | 3 ++- + 3 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/include/proto/queue.h b/include/proto/queue.h +index be78b53..77964fe 100644 +--- a/include/proto/queue.h ++++ b/include/proto/queue.h +@@ -64,11 +64,11 @@ static inline struct pendconn *pendconn_from_px(const struct proxy *px) { + } + + /* returns 0 if nothing has to be done for server regarding queued connections, +- * and non-zero otherwise. If the server is down, we always return zero. Suited for +- * and if/else usage. ++ * and non-zero otherwise. If the server is down, we only check its own queue. Suited ++ * for and if/else usage. + */ + static inline int may_dequeue_tasks(const struct server *s, const struct proxy *p) { +- return (s && (s->state & SRV_RUNNING) && (s->nbpend || p->nbpend) && ++ return (s && (s->nbpend || (p->nbpend && (s->state & SRV_RUNNING))) && + (!s->maxconn || s->cur_sess < srv_dynamic_maxconn(s))); + } + +diff --git a/src/queue.c b/src/queue.c +index 905994a..c5ea0bb 100644 +--- a/src/queue.c ++++ b/src/queue.c +@@ -89,6 +89,10 @@ void process_srv_queue(struct server *s) + * returned. Note that neither nor may be NULL. + * Priority is given to the oldest request in the queue if both and + * have pending requests. This ensures that no request will be left unserved. ++ * The queue is not considered if the server is not RUNNING. The ++ * queue is still considered in this case, because if some connections remain ++ * there, it means that some requests have been forced there after it was seen ++ * down (eg: due to option persist). + * The session is immediately marked as "assigned", and both its and + * are set to , + */ +@@ -100,7 +104,7 @@ struct session *pendconn_get_next_sess(struct server *srv, struct proxy *px) + ps = pendconn_from_srv(srv); + pp = pendconn_from_px(px); + /* we want to get the definitive pendconn in */ +- if (!pp) { ++ if (!pp || !(srv->state & SRV_RUNNING)) { + if (!ps) + return NULL; + } else { +diff --git a/src/session.c b/src/session.c +index e3a736d..0d6ad8d 100644 +--- a/src/session.c ++++ b/src/session.c +@@ -41,8 +41,9 @@ void session_free(struct session *s) + + if (s->pend_pos) + pendconn_free(s->pend_pos); +- if (s->srv) /* there may be requests left pending in queue */ ++ if (s->srv && may_dequeue_tasks(s->srv, s->be)) /* there may be requests left pending in queue */ + process_srv_queue(s->srv); ++ + if (unlikely(s->srv_conn)) { + /* the session still has a reserved slot on a server, but + * it should normally be only the same as the one above, +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0057-BUG-ensure-that-we-correctly-re-start-old-process-in.patch +++ haproxy-1.3.15.2/debian/patches/0057-BUG-ensure-that-we-correctly-re-start-old-process-in.patch @@ -0,0 +1,39 @@ +From 83a1540ec51d20697b6c6f86e63dc5e82efc0b72 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 9 Jun 2009 14:36:00 +0200 +Subject: [PATCH 57/62] [BUG] ensure that we correctly re-start old process in case of error + +When a new process fails to grab some ports, it sends a signal to +the old process in order to release them. Then it tries to bind +again. If it still fails (eg: one of the ports is bound to a +completely different process), it must send the continue signal +to the old process so that this one re-binds to the ports. This +is correctly done, but the newly bound ports are not released +first, which sometimes causes the old process to remain running +with no port bound. The fix simply consists in unbinding all +ports before sending the signal to the old process. +(cherry picked from commit f68da4603a092f35af627c459dbc714d9fa796e9) +(cherry picked from commit f20cad6b3214f2b1b3db7fbeeecc0ef109185c2d) +--- + src/haproxy.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/src/haproxy.c b/src/haproxy.c +index c4b83a7..e57dd09 100644 +--- a/src/haproxy.c ++++ b/src/haproxy.c +@@ -871,8 +871,10 @@ int main(int argc, char **argv) + + /* Note: start_proxies() sends an alert when it fails. */ + if ((err & ~ERR_WARN) != ERR_NONE) { +- if (retry != MAX_START_RETRIES && nb_oldpids) ++ if (retry != MAX_START_RETRIES && nb_oldpids) { ++ protocol_unbind_all(); /* cleanup everything we can */ + tell_old_pids(SIGTTIN); ++ } + exit(1); + } + +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0052-BUG-O-1-pollers-should-check-their-FD-before-closing.patch +++ haproxy-1.3.15.2/debian/patches/0052-BUG-O-1-pollers-should-check-their-FD-before-closing.patch @@ -0,0 +1,155 @@ +From 0d27ec2050a3208150af5dcaeda9dab7a53fdaf7 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 10 May 2009 10:18:54 +0200 +Subject: [PATCH 52/62] [BUG] O(1) pollers should check their FD before closing it + +[cherry-picked from commit d79e79b436144654d10124de7d5fd4c896ac0487] + +epoll, sepoll and kqueue pollers should check that their fd is not +closed before attempting to close it, otherwise we can end up with +multiple closes of fd #0 upon exit, which is harmless but dirty. +--- + src/ev_epoll.c | 13 +++++++++---- + src/ev_kqueue.c | 14 ++++++++++---- + src/ev_sepoll.c | 13 +++++++++---- + 3 files changed, 28 insertions(+), 12 deletions(-) + +diff --git a/src/ev_epoll.c b/src/ev_epoll.c +index 0ce68b0..2c34524 100644 +--- a/src/ev_epoll.c ++++ b/src/ev_epoll.c +@@ -308,7 +308,7 @@ REGPRM1 static int _do_init(struct poller *p) + free(epoll_events); + fail_ee: + close(epoll_fd); +- epoll_fd = 0; ++ epoll_fd = -1; + fail_fd: + p->pref = 0; + return 0; +@@ -331,8 +331,10 @@ REGPRM1 static void _do_term(struct poller *p) + if (epoll_events) + free(epoll_events); + +- close(epoll_fd); +- epoll_fd = 0; ++ if (epoll_fd >= 0) { ++ close(epoll_fd); ++ epoll_fd = -1; ++ } + + chg_ptr = NULL; + chg_list = NULL; +@@ -366,7 +368,8 @@ REGPRM1 static int _do_test(struct poller *p) + */ + REGPRM1 static int _do_fork(struct poller *p) + { +- close(epoll_fd); ++ if (epoll_fd >= 0) ++ close(epoll_fd); + epoll_fd = epoll_create(global.maxsock + 1); + if (epoll_fd < 0) + return 0; +@@ -385,6 +388,8 @@ static void _do_register(void) + + if (nbpollers >= MAX_POLLERS) + return; ++ ++ epoll_fd = -1; + p = &pollers[nbpollers++]; + + p->name = "epoll"; +diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c +index f34cdc3..46584b3 100644 +--- a/src/ev_kqueue.c ++++ b/src/ev_kqueue.c +@@ -186,7 +186,7 @@ REGPRM1 static int _do_init(struct poller *p) + free(kev); + fail_kev: + close(kqueue_fd); +- kqueue_fd = 0; ++ kqueue_fd = -1; + fail_fd: + p->pref = 0; + return 0; +@@ -204,8 +204,11 @@ REGPRM1 static void _do_term(struct poller *p) + free(fd_evts[DIR_RD]); + if (kev) + free(kev); +- close(kqueue_fd); +- kqueue_fd = 0; ++ ++ if (kqueue_fd >= 0) { ++ close(kqueue_fd); ++ kqueue_fd = -1; ++ } + + p->private = NULL; + p->pref = 0; +@@ -233,7 +236,8 @@ REGPRM1 static int _do_test(struct poller *p) + */ + REGPRM1 static int _do_fork(struct poller *p) + { +- close(kqueue_fd); ++ if (kqueue_fd >= 0) ++ close(kqueue_fd); + kqueue_fd = kqueue(); + if (kqueue_fd < 0) + return 0; +@@ -252,6 +256,8 @@ static void _do_register(void) + + if (nbpollers >= MAX_POLLERS) + return; ++ ++ kqueue_fd = -1; + p = &pollers[nbpollers++]; + + p->name = "kqueue"; +diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c +index db35423..417cbcf 100644 +--- a/src/ev_sepoll.c ++++ b/src/ev_sepoll.c +@@ -526,7 +526,7 @@ REGPRM1 static int _do_init(struct poller *p) + free(epoll_events); + fail_ee: + close(epoll_fd); +- epoll_fd = 0; ++ epoll_fd = -1; + fail_fd: + p->pref = 0; + return 0; +@@ -545,8 +545,10 @@ REGPRM1 static void _do_term(struct poller *p) + if (epoll_events) + free(epoll_events); + +- close(epoll_fd); +- epoll_fd = 0; ++ if (epoll_fd >= 0) { ++ close(epoll_fd); ++ epoll_fd = -1; ++ } + + fd_list = NULL; + spec_list = NULL; +@@ -579,7 +581,8 @@ REGPRM1 static int _do_test(struct poller *p) + */ + REGPRM1 static int _do_fork(struct poller *p) + { +- close(epoll_fd); ++ if (epoll_fd >= 0) ++ close(epoll_fd); + epoll_fd = epoll_create(global.maxsock + 1); + if (epoll_fd < 0) + return 0; +@@ -598,6 +601,8 @@ static void _do_register(void) + + if (nbpollers >= MAX_POLLERS) + return; ++ ++ epoll_fd = -1; + p = &pollers[nbpollers++]; + + p->name = "sepoll"; +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0037-BUG-typo-in-timeout-error-reporting-report-res-and-n.patch +++ haproxy-1.3.15.2/debian/patches/0037-BUG-typo-in-timeout-error-reporting-report-res-and-n.patch @@ -0,0 +1,26 @@ +From 5c91210297ec91d805211595d40bab0188b62902 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Fri, 6 Mar 2009 08:05:40 +0100 +Subject: [PATCH 37/62] [BUG] typo in timeout error reporting : report *res and not *err + (cherry picked from commit bb9251ed8fc4e79c40f5b4459d20cecb4428fb1c) + +--- + src/proxy.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/src/proxy.c b/src/proxy.c +index 3581329..219837c 100644 +--- a/src/proxy.c ++++ b/src/proxy.c +@@ -145,7 +145,7 @@ int proxy_parse_timeout(const char **args, struct proxy *proxy, + + res = parse_time_err(args[1], &timeout, TIME_UNIT_MS); + if (res) { +- snprintf(err, errlen, "unexpected character '%c' in %s timeout", *err, name); ++ snprintf(err, errlen, "unexpected character '%c' in %s timeout", *res, name); + return -1; + } + +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0042-BUG-server-check-intervals-must-not-be-null.patch +++ haproxy-1.3.15.2/debian/patches/0042-BUG-server-check-intervals-must-not-be-null.patch @@ -0,0 +1,99 @@ +From ea3caccc0f62bd9a2a96bf205698e480e57f497b Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sat, 21 Mar 2009 18:58:32 +0100 +Subject: [PATCH 42/62] [BUG] server check intervals must not be null + +[cherry-picked from commit e38388033f3df181ff6a2ee227789cd743d17dc1] + +If server check interval is null, we might end up looping in +process_srv_chk(). + +Prevent those values from being zero and add some control in +process_srv_chk() against infinite loops. +--- + src/cfgparse.c | 20 ++++++++++++++++++++ + src/checks.c | 9 +++++++++ + 2 files changed, 29 insertions(+), 0 deletions(-) + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index d01b475..2d226ba 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -1638,6 +1638,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) + file, linenum, *err, newsrv->id); + return -1; + } ++ if (val <= 0) { ++ Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n", ++ file, linenum, val, args[cur_arg], newsrv->id); ++ return -1; ++ } + newsrv->inter = val; + cur_arg += 2; + } +@@ -1648,6 +1653,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) + file, linenum, *err, newsrv->id); + return -1; + } ++ if (val <= 0) { ++ Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n", ++ file, linenum, val, args[cur_arg], newsrv->id); ++ return -1; ++ } + newsrv->fastinter = val; + cur_arg += 2; + } +@@ -1658,6 +1668,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) + file, linenum, *err, newsrv->id); + return -1; + } ++ if (val <= 0) { ++ Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n", ++ file, linenum, val, args[cur_arg], newsrv->id); ++ return -1; ++ } + newsrv->downinter = val; + cur_arg += 2; + } +@@ -1704,6 +1719,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) + file, linenum, *err, newsrv->id); + return -1; + } ++ if (val <= 0) { ++ Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n", ++ file, linenum, val, args[cur_arg], newsrv->id); ++ return -1; ++ } + newsrv->slowstart = (val + 999) / 1000; + cur_arg += 2; + } +diff --git a/src/checks.c b/src/checks.c +index 82de260..a0bca95 100644 +--- a/src/checks.c ++++ b/src/checks.c +@@ -529,6 +529,7 @@ static int event_srv_chk_r(int fd) + void process_chk(struct task *t, struct timeval *next) + { + __label__ new_chk, out; ++ int attempts = 0; + struct server *s = t->context; + struct sockaddr_in sa; + int fd; +@@ -537,6 +538,14 @@ void process_chk(struct task *t, struct timeval *next) + //fprintf(stderr, "process_chk: task=%p\n", t); + + new_chk: ++ if (attempts++ > 0) { ++ /* we always fail to create a server, let's stop insisting... */ ++ while (tv_isle(&t->expire, &now)) ++ tv_ms_add(&t->expire, &t->expire, s->inter); ++ task_queue(t); /* restore t to its place in the task list */ ++ *next = t->expire; ++ goto out; ++ } + fd = s->curfd; + if (fd < 0) { /* no check currently running */ + //fprintf(stderr, "process_chk: 2\n"); +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0016-BUG-do-not-try-to-pause-backends-during-reload.patch +++ haproxy-1.3.15.2/debian/patches/0016-BUG-do-not-try-to-pause-backends-during-reload.patch @@ -0,0 +1,79 @@ +From eab5c70f93c0a44223f706f6c120ad8d59f28796 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Fri, 10 Oct 2008 17:51:34 +0200 +Subject: [PATCH 16/62] [BUG] do not try to pause backends during reload + +During a configuration reload, haproxy tried to pause all proxies. +Unfortunately, it also tried to pause backends, which would fail +and cause trouble to the new process since the port was still bound. +--- + src/proxy.c | 27 ++++++++++++++------------- + 1 files changed, 14 insertions(+), 13 deletions(-) + +diff --git a/src/proxy.c b/src/proxy.c +index c0e7ab6..6fad76e 100644 +--- a/src/proxy.c ++++ b/src/proxy.c +@@ -388,8 +388,8 @@ void soft_stop(void) + tv_now(&now); /* else, the old time before select will be used */ + while (p) { + if (p->state != PR_STSTOPPED) { +- Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace); +- send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace); ++ Warning("Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); ++ send_log(p, LOG_WARNING, "Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); + tv_ms_add(&p->stop_time, &now, p->grace); + } + p = p->next; +@@ -436,16 +436,17 @@ void pause_proxies(void) + p = proxy; + tv_now(&now); /* else, the old time before select will be used */ + while (p) { +- if (p->state != PR_STERROR && ++ if (p->cap & PR_CAP_FE && ++ p->state != PR_STERROR && + p->state != PR_STSTOPPED && + p->state != PR_STPAUSED) { +- Warning("Pausing proxy %s.\n", p->id); +- send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id); ++ Warning("Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); ++ send_log(p, LOG_WARNING, "Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); + pause_proxy(p); + if (p->state != PR_STPAUSED) { + err |= 1; +- Warning("Proxy %s failed to enter pause mode.\n", p->id); +- send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id); ++ Warning("%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); ++ send_log(p, LOG_WARNING, "%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); + } + } + p = p->next; +@@ -472,8 +473,8 @@ void listen_proxies(void) + tv_now(&now); /* else, the old time before select will be used */ + while (p) { + if (p->state == PR_STPAUSED) { +- Warning("Enabling proxy %s.\n", p->id); +- send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id); ++ Warning("Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); ++ send_log(p, LOG_WARNING, "Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); + + for (l = p->listen; l != NULL; l = l->next) { + if (listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0) { +@@ -491,10 +492,10 @@ void listen_proxies(void) + else + port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port); + +- Warning("Port %d busy while trying to enable proxy %s.\n", +- port, p->id); +- send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n", +- port, p->id); ++ Warning("Port %d busy while trying to enable %s %s.\n", ++ port, proxy_cap_str(p->cap), p->id); ++ send_log(p, LOG_WARNING, "Port %d busy while trying to enable %s %s.\n", ++ port, proxy_cap_str(p->cap), p->id); + /* Another port might have been enabled. Let's stop everything. */ + pause_proxy(p); + break; +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0025-BUG-do-not-dequeue-requests-on-a-dead-server.patch +++ haproxy-1.3.15.2/debian/patches/0025-BUG-do-not-dequeue-requests-on-a-dead-server.patch @@ -0,0 +1,43 @@ +From 80b286a064eaec828b7fd10e98e3f945e8b244f3 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 30 Nov 2008 21:51:58 +0100 +Subject: [PATCH 25/62] [BUG] do not dequeue requests on a dead server + +Kai Krueger reported a problem when a server goes down with active +connections. A lot of connections were drained by that server. Kai +did an amazing job at tracking this bug down to the dequeuing +mechanism which forgets to check the server state before allowing +a request to be sent to a server. + +The problem occurs more often with long requests, which have a chance +to complete after the server is completely marked down, and to find +requests in the global queue which have not yet been fetched by other +servers. + +The fix consists in ensuring that a server is up before sending it +any new request from the queue. +--- + include/proto/queue.h | 5 +++-- + 1 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/proto/queue.h b/include/proto/queue.h +index 6899aee..be78b53 100644 +--- a/include/proto/queue.h ++++ b/include/proto/queue.h +@@ -64,10 +64,11 @@ static inline struct pendconn *pendconn_from_px(const struct proxy *px) { + } + + /* returns 0 if nothing has to be done for server regarding queued connections, +- * and non-zero otherwise. Suited for and if/else usage. ++ * and non-zero otherwise. If the server is down, we always return zero. Suited for ++ * and if/else usage. + */ + static inline int may_dequeue_tasks(const struct server *s, const struct proxy *p) { +- return (s && (s->nbpend || p->nbpend) && ++ return (s && (s->state & SRV_RUNNING) && (s->nbpend || p->nbpend) && + (!s->maxconn || s->cur_sess < srv_dynamic_maxconn(s))); + } + +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0017-BUG-ensure-that-listeners-from-disabled-proxies-are-.patch +++ haproxy-1.3.15.2/debian/patches/0017-BUG-ensure-that-listeners-from-disabled-proxies-are-.patch @@ -0,0 +1,97 @@ +From a944218e9c1d5ff1aca34609146389dc680335b7 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 12 Oct 2008 12:07:48 +0200 +Subject: [PATCH 17/62] [BUG] ensure that listeners from disabled proxies are correctly unbound. + +There is a problem when an instance is marked "disabled". Its ports are +still bound but will not be unbound upon termination. This causes processes +to accumulate during soft restarts, and might even cause failures to restart +new ones due to the inability to bind to the same port. + +The ideal solution would be to bind all ports at the end of the configuration +parsing. An acceptable workaround is to unbind all listeners of disabled +proxies. This is what the current patch does. +--- + include/proto/proxy.h | 1 + + src/cfgparse.c | 2 ++ + src/proxy.c | 32 +++++++++++++++++++++++--------- + 3 files changed, 26 insertions(+), 9 deletions(-) + +diff --git a/include/proto/proxy.h b/include/proto/proxy.h +index 7268bfa..7239478 100644 +--- a/include/proto/proxy.h ++++ b/include/proto/proxy.h +@@ -30,6 +30,7 @@ int start_proxies(int verbose); + void maintain_proxies(struct timeval *next); + void soft_stop(void); + void pause_proxy(struct proxy *p); ++void stop_proxy(struct proxy *p); + void pause_proxies(void); + void listen_proxies(void); + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index d34bfbe..b33800c 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -2726,6 +2726,8 @@ int readcfgfile(const char *file) + struct listener *listener; + + if (curproxy->state == PR_STSTOPPED) { ++ /* ensure we don't keep listeners uselessly bound */ ++ stop_proxy(curproxy); + curproxy = curproxy->next; + continue; + } +diff --git a/src/proxy.c b/src/proxy.c +index 6fad76e..3581329 100644 +--- a/src/proxy.c ++++ b/src/proxy.c +@@ -351,15 +351,7 @@ void maintain_proxies(struct timeval *next) + if (t == 0) { + Warning("Proxy %s stopped.\n", p->id); + send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id); +- +- for (l = p->listen; l != NULL; l = l->next) { +- unbind_listener(l); +- if (l->state >= LI_ASSIGNED) { +- delete_listener(l); +- listeners--; +- } +- } +- p->state = PR_STSTOPPED; ++ stop_proxy(p); + /* try to free more memory */ + pool_gc2(); + } +@@ -421,6 +413,28 @@ void pause_proxy(struct proxy *p) + } + } + ++ ++/* ++ * This function completely stops a proxy and releases its listeners. It has ++ * to be called when going down in order to release the ports so that another ++ * process may bind to them. It must also be called on disabled proxies at the ++ * end of start-up. When all listeners are closed, the proxy is set to the ++ * PR_STSTOPPED state. ++ */ ++void stop_proxy(struct proxy *p) ++{ ++ struct listener *l; ++ ++ for (l = p->listen; l != NULL; l = l->next) { ++ unbind_listener(l); ++ if (l->state >= LI_ASSIGNED) { ++ delete_listener(l); ++ listeners--; ++ } ++ } ++ p->state = PR_STSTOPPED; ++} ++ + /* + * This function temporarily disables listening so that another new instance + * can start listening. It is designed to be called upon reception of a +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0035-BUG-the-source-keyword-must-first-clear-optional-set.patch +++ haproxy-1.3.15.2/debian/patches/0035-BUG-the-source-keyword-must-first-clear-optional-set.patch @@ -0,0 +1,35 @@ +From 15b939fbdd5885b6814454c273e64b8cd348b59d Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 1 Mar 2009 08:27:21 +0100 +Subject: [PATCH 35/62] [BUG] the "source" keyword must first clear optional settings + +Problem reported by John Lauro. When "source ... usesrc ..." is +set in the defaults section, it is not possible anymore to remove +the "usesrc" part when declaring a more precise "source" in a +backend. The only workaround was to declare it by server. + +We need to clear optional settings when declaring a new "source". +(cherry picked from commit 368480cf4570a0d6448741c704aebd53ac467aa9) +--- + src/cfgparse.c | 5 ++++- + 1 files changed, 4 insertions(+), 1 deletions(-) + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index d09d6da..d01b475 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -1903,7 +1903,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) + #endif + return -1; + } +- ++ ++ /* we must first clear any optional default setting */ ++ curproxy->options &= ~PR_O_TPXY_MASK; ++ + curproxy->source_addr = *str2sa(args[1]); + curproxy->options |= PR_O_BIND_SRC; + if (!strcmp(args[2], "usesrc")) { /* address to use outside */ +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0001-BUG-disable-buffer-read-timeout-when-reading-stats.patch +++ haproxy-1.3.15.2/debian/patches/0001-BUG-disable-buffer-read-timeout-when-reading-stats.patch @@ -0,0 +1,29 @@ +From 80f35306e97e8ae762f81a178c8c225b5bbac91e Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 29 Jun 2008 16:38:43 +0200 +Subject: [PATCH 01/62] [BUG] disable buffer read timeout when reading stats + +The buffer read timeouts were not reset when stats were produced. This +caused unneeded wakeups. +(cherry picked from commit 284c7b319566a66d5b742c905072175aac6445e1) +--- + src/proto_http.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/src/proto_http.c b/src/proto_http.c +index 0311748..e36f4b0 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -5062,6 +5062,9 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend) + /* The request is valid, the user is authenticated. Let's start sending + * data. + */ ++ EV_FD_CLR(t->cli_fd, DIR_RD); ++ buffer_shutr(t->req); ++ buffer_shutr(t->rep); + t->cli_state = CL_STSHUTR; + t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */ + t->logs.tv_request = now; +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0018-BUG-acl-related-keywords-are-not-allowed-in-defaults.patch +++ haproxy-1.3.15.2/debian/patches/0018-BUG-acl-related-keywords-are-not-allowed-in-defaults.patch @@ -0,0 +1,82 @@ +From 1c90a6ec20946a713e9c93995a8e91ed3eeb9da4 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Sun, 12 Oct 2008 17:26:37 +0200 +Subject: [PATCH 18/62] [BUG] acl-related keywords are not allowed in defaults sections + +Using an ACL-related keyword in the defaults section causes a +segfault during parsing because the list headers are not initialized. +We must initialize list headers for default instance and reject +keywords relying on ACLs. +--- + src/cfgparse.c | 27 +++++++++++++++++++++++++++ + 1 files changed, 27 insertions(+), 0 deletions(-) + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index b33800c..038915a 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -516,6 +516,13 @@ static void init_default_instance() + defproxy.maxconn = cfg_maxpconn; + defproxy.conn_retries = CONN_RETRIES; + defproxy.logfac1 = defproxy.logfac2 = -1; /* log disabled */ ++ ++ LIST_INIT(&defproxy.pendconns); ++ LIST_INIT(&defproxy.acl); ++ LIST_INIT(&defproxy.block_cond); ++ LIST_INIT(&defproxy.mon_fail_cond); ++ LIST_INIT(&defproxy.switching_rules); ++ + proxy_reset_timeouts(&defproxy); + } + +@@ -837,6 +844,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) + curproxy->state = PR_STNEW; + } + else if (!strcmp(args[0], "acl")) { /* add an ACL */ ++ if (curproxy == &defproxy) { ++ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); ++ return -1; ++ } ++ + err = invalid_char(args[1]); + if (err) { + Alert("parsing [%s:%d] : character '%c' is not permitted in acl name '%s'.\n", +@@ -1076,6 +1088,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) + int pol = ACL_COND_NONE; + struct acl_cond *cond; + ++ if (curproxy == &defproxy) { ++ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); ++ return -1; ++ } ++ + if (!strcmp(args[1], "if")) + pol = ACL_COND_IF; + else if (!strcmp(args[1], "unless")) +@@ -1099,6 +1116,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) + struct acl_cond *cond; + struct switching_rule *rule; + ++ if (curproxy == &defproxy) { ++ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); ++ return -1; ++ } ++ + if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL)) + return 0; + +@@ -1376,6 +1398,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv) + } + } + else if (!strcmp(args[0], "monitor")) { ++ if (curproxy == &defproxy) { ++ Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); ++ return -1; ++ } ++ + if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL)) + return 0; + +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0007-BUG-server-timeout-was-not-considered-in-some-circum.patch +++ haproxy-1.3.15.2/debian/patches/0007-BUG-server-timeout-was-not-considered-in-some-circum.patch @@ -0,0 +1,46 @@ +From df82605d3e73573ae842a1ddaf418997bef33274 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Mon, 11 Aug 2008 10:35:07 +0200 +Subject: [PATCH 07/62] [BUG] server timeout was not considered in some circumstances + +Due to a copy-paste typo, the client timeout was refreshed instead +of the server's when waiting for server response. This means that +the server's timeout remained eternity. + +(cherry picked from commit 9f1f24bb7fb8ebd6b43b5fee1bda0afbdbcb768e) +--- + src/stream_sock.c | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/stream_sock.c b/src/stream_sock.c +index 08cc65b..8bfc55b 100644 +--- a/src/stream_sock.c ++++ b/src/stream_sock.c +@@ -174,7 +174,7 @@ int stream_sock_read(int fd) { + * have at least read something. + */ + +- if (b->flags & BF_PARTIAL_READ) { ++ if (b->flags & BF_PARTIAL_READ && tv_isset(&b->rex)) { + if (tv_add_ifset(&b->rex, &now, &b->rto)) + goto out_wakeup; + out_eternity: +@@ -330,13 +330,13 @@ int stream_sock_write(int fd) { + * written something. + */ + +- if (b->flags & BF_PARTIAL_WRITE) { ++ if (b->flags & BF_PARTIAL_WRITE && tv_isset(&b->wex)) { + if (tv_add_ifset(&b->wex, &now, &b->wto)) { + /* FIXME: to prevent the client from expiring read timeouts during writes, + * we refresh it. A solution would be to merge read+write timeouts into a + * unique one, although that needs some study particularly on full-duplex + * TCP connections. */ +- if (!(b->flags & BF_SHUTR_STATUS)) ++ if (!(b->flags & BF_SHUTR_STATUS) && tv_isset(&b->rex)) + b->rex = b->wex; + goto out_wakeup; + } +-- +1.6.5 + only in patch2: unchanged: --- haproxy-1.3.15.2.orig/debian/patches/0033-BUG-inform-the-user-when-root-is-expected-but-not-se.patch +++ haproxy-1.3.15.2/debian/patches/0033-BUG-inform-the-user-when-root-is-expected-but-not-se.patch @@ -0,0 +1,40 @@ +From 62b2febcdb7a6f25df84d2b0b887b84540528f66 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Wed, 4 Feb 2009 18:02:48 +0100 +Subject: [PATCH 33/62] [BUG] inform the user when root is expected but not set + +When a plain user runs haproxy as non-root but some options require +root, let's inform him. +(cherry picked from commit 4e30ed73f4b902b076f765c3e2370ef0a034a648) +--- + src/haproxy.c | 10 +++++++++- + 1 files changed, 9 insertions(+), 1 deletions(-) + +diff --git a/src/haproxy.c b/src/haproxy.c +index 6eca3bf..39b8918 100644 +--- a/src/haproxy.c ++++ b/src/haproxy.c +@@ -977,11 +977,19 @@ int main(int argc, char **argv) + + if ((global.last_checks & LSTCHK_NETADM) && global.uid) { + Alert("[%s.main()] Some configuration options require full privileges, so global.uid cannot be changed.\n" +- "", argv[0], global.gid); ++ "", argv[0]); + protocol_unbind_all(); + exit(1); + } + ++ /* If the user is not root, we'll still let him try the configuration ++ * but we inform him that unexpected behaviour may occur. ++ */ ++ if ((global.last_checks & LSTCHK_NETADM) && getuid()) ++ Warning("[%s.main()] Some options which require full privileges" ++ " might not work well.\n" ++ "", argv[0]); ++ + /* chroot if needed */ + if (global.chroot != NULL) { + if (chroot(global.chroot) == -1) { +-- +1.6.5 +