package: haproxy
authorThomas Heil <heil@terminal-consulting.de>
Thu, 10 Jan 2013 23:47:03 +0000 (23:47 +0000)
committerThomas Heil <heil@terminal-consulting.de>
Thu, 10 Jan 2013 23:47:03 +0000 (23:47 +0000)
 - add missing patches
 - add patch number to version

SVN-Revision: 35091

25 files changed:
net/haproxy/Makefile
net/haproxy/patches/0001-BUG-MINOR-config-use-a-copy-of-the-file-name-i-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0002-BUG-MINOR-epoll-correctly-disable-FD-polling-i-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0003-CONTRIB-halog-sort-URLs-by-avg-bytes_read-or-t-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0004-MINOR-halog-sort-output-by-cookie-code-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0005-BUG-MINOR-halog-ad-ac-report-the-correct-numbe-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0006-BUG-MINOR-halog-fix-help-message-for-ut-uto-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0007-BUG-MEDIUM-http-set-DONTWAIT-on-data-when-swit-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0008-BUG-MEDIUM-command-line-option-D-must-have-pre-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0009-BUG-fix-garbage-data-when-http-send-name-heade-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/001-haproxy-1.4.x-sendproxy.patch
net/haproxy/patches/0010-OPTIM-halog-keep-a-fast-path-for-the-lines-cou-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0011-MINOR-halog-add-a-parameter-to-limit-output-li-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0012-BUG-halog-fix-broken-output-limitation-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0013-MEDIUM-checks-avoid-accumulating-TIME_WAITs-du-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0014-MEDIUM-checks-prevent-TIME_WAITs-from-appearin-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0015-BUG-MAJOR-cli-show-sess-id-may-randomly-corrup-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0016-BUG-MINOR-http-don-t-report-client-aborts-as-s-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0017-BUG-MINOR-http-don-t-log-a-503-on-client-error-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0018-BUG-MEDIUM-tcp-process-could-theorically-crash-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0019-BUG-MINOR-http-don-t-abort-client-connection-o-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0020-BUILD-no-need-to-clean-up-when-making-git-tar-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0021-MINOR-http-always-report-PR-flags-for-redirect-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0022-BUG-MINOR-time-frequency-counters-are-not-tota-1.4.22.diff [new file with mode: 0644]
net/haproxy/patches/0023-BUG-MINOR-http-don-t-process-abortonclose-when-1.4.22.diff [new file with mode: 0644]

index e0928174a5748d83494860c2a2fcb85b99f526ee..3c5a8a84d43d3539d500c39b563ec48596c10ec2 100644 (file)
@@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=haproxy
 PKG_VERSION:=1.4.22
-PKG_RELEASE:=1
+PKG_RELEASE:=23
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=http://haproxy.1wt.eu/download/1.4/src
@@ -44,6 +44,7 @@ define Build/Compile
                LD="$(TARGET_CC)" \
                LDFLAGS="$(TARGET_LDFLAGS)" \
                SMALL_OPTS="-DBUFSIZE=16384 -DMAXREWRITE=8192 -DSYSTEM_MAXCONN=65530" USE_LINUX_TPROXY=1 USE_LINUX_SPLICE=1 \
+               VERSION="$(PKG_VERSION)-patch$(PKG_RELEASE)" \
                all install
 endef
 
diff --git a/net/haproxy/patches/0001-BUG-MINOR-config-use-a-copy-of-the-file-name-i-1.4.22.diff b/net/haproxy/patches/0001-BUG-MINOR-config-use-a-copy-of-the-file-name-i-1.4.22.diff
new file mode 100644 (file)
index 0000000..d77d4ce
--- /dev/null
@@ -0,0 +1,75 @@
+From 60f05a8eae1afda44d62066445a0c072659a1aa1 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Thu, 4 Oct 2012 08:01:43 +0200
+Subject: BUG/MINOR: config: use a copy of the file name in proxy configurations
+
+Each proxy contains a reference to the original config file and line
+number where it was declared. The pointer used is just a reference to
+the one passed to the function instead of being duplicated. The effect
+is that it is not valid anymore at the end of the parsing and that all
+proxies will be enumerated as coming from the same file on some late
+configuration errors. This may happen for exmaple when reporting SSL
+certificate issues.
+
+By copying using strdup(), we avoid this issue.
+
+1.4 has the same issue, though no report of the proxy file name is done
+out of the config section. Anyway a backport is recommended to ease
+post-mortem analysis.
+(cherry picked from commit 8113a5d78f2d2abe942f88a3a4df9f8bb5e535ba)
+---
+ include/types/proxy.h |    2 +-
+ src/cfgparse.c        |    4 ++--
+ src/haproxy.c         |    1 +
+ 3 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/include/types/proxy.h b/include/types/proxy.h
+index 1773658..a06078a 100644
+--- a/include/types/proxy.h
++++ b/include/types/proxy.h
+@@ -320,7 +320,7 @@ struct proxy {
+       int no_options2;                        /* PR_O2_* */
+       struct {
+-              const char *file;               /* file where the section appears */
++              char *file;                     /* file where the section appears */
+               int line;                       /* line where the section appears */
+               struct eb32_node id;            /* place in the tree of used IDs */
+               struct eb_root used_listener_id;/* list of listener IDs in use */
+diff --git a/src/cfgparse.c b/src/cfgparse.c
+index 643f065..90fdbff 100644
+--- a/src/cfgparse.c
++++ b/src/cfgparse.c
+@@ -1136,7 +1136,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
+               init_new_proxy(curproxy);
+               curproxy->next = proxy;
+               proxy = curproxy;
+-              curproxy->conf.file = file;
++              curproxy->conf.file = strdup(file);
+               curproxy->conf.line = linenum;
+               curproxy->last_change = now.tv_sec;
+               curproxy->id = strdup(args[1]);
+@@ -3425,7 +3425,7 @@ stats_error_parsing:
+                       newsrv->next = curproxy->srv;
+                       curproxy->srv = newsrv;
+                       newsrv->proxy = curproxy;
+-                      newsrv->conf.file = file;
++                      newsrv->conf.file = strdup(file);
+                       newsrv->conf.line = linenum;
+                       LIST_INIT(&newsrv->pendconns);
+diff --git a/src/haproxy.c b/src/haproxy.c
+index 6141a5b..2944462 100644
+--- a/src/haproxy.c
++++ b/src/haproxy.c
+@@ -732,6 +732,7 @@ void deinit(void)
+       int i;
+       while (p) {
++              free(p->conf.file);
+               free(p->id);
+               free(p->check_req);
+               free(p->cookie_name);
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0002-BUG-MINOR-epoll-correctly-disable-FD-polling-i-1.4.22.diff b/net/haproxy/patches/0002-BUG-MINOR-epoll-correctly-disable-FD-polling-i-1.4.22.diff
new file mode 100644 (file)
index 0000000..e02cf47
--- /dev/null
@@ -0,0 +1,53 @@
+From 72ce4c8f4e0531c50b3a0914d77858440d16d914 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Thu, 4 Oct 2012 21:54:41 +0200
+Subject: BUG/MINOR: epoll: correctly disable FD polling in fd_rem()
+
+When calling fd_rem(), the polling was not correctly disabled because the
+->prev state was set to zero instead of the previous value. fd_rem() is
+very rarely used, only just before closing a socket.
+
+The effect is that upon an error reported at the connection level, if the
+task assigned to the connection was too slow to be woken up because of too
+many other tasks in the run queue, the FD was still not disabled and caused
+the connection handler to be called again with the same event until the task
+was finally executed to close the fd.
+
+This issue only affects the epoll poller, not the sepoll variant nor any of
+the other ones.
+
+It was already present in 1.4 and even 1.3 with the same almost unnoticeable
+effects. The bug can in fact only be discovered during development where it
+emphasizes other bugs.
+
+It should be backported anyway.
+(cherry picked from commit f8cfa447c676849e1d1b007353d4ea2f7231e4a0)
+---
+ src/ev_epoll.c |    8 ++++++--
+ 1 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/ev_epoll.c b/src/ev_epoll.c
+index b976868..0b22da6 100644
+--- a/src/ev_epoll.c
++++ b/src/ev_epoll.c
+@@ -194,11 +194,15 @@ REGPRM2 static int __fd_clr(const int fd, int dir)
+ REGPRM1 static void __fd_rem(int fd)
+ {
+       uint32_t ofs = FD2OFS(fd);
++      uint32_t old_evt;
+-      if (unlikely(!((fd_evts[ofs] >> FD2BIT(fd)) & 3)))
++      old_evt = fd_evts[ofs] >> FD2BIT(fd);
++      old_evt &= 3;
++
++      if (unlikely(!old_evt))
+               return;
+-      alloc_chg_list(fd, 0);
++      alloc_chg_list(fd, old_evt);
+       fd_evts[ofs] &= ~FD2MSK(fd);
+       return;
+ }
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0003-CONTRIB-halog-sort-URLs-by-avg-bytes_read-or-t-1.4.22.diff b/net/haproxy/patches/0003-CONTRIB-halog-sort-URLs-by-avg-bytes_read-or-t-1.4.22.diff
new file mode 100644 (file)
index 0000000..fa63d87
--- /dev/null
@@ -0,0 +1,191 @@
+From 69eeb17615cd032ec7b3a9496ddb811095e92cb4 Mon Sep 17 00:00:00 2001
+From: Baptiste <bedis9@gmail.com>
+Date: Sat, 8 Sep 2012 23:10:03 +0200
+Subject: CONTRIB: halog: sort URLs by avg bytes_read or total bytes_read
+
+The patch attached to this mail brings ability to sort URLs by
+averaged bytes read and total bytes read in HALog tool.
+In most cases, bytes read is also the object size.
+The purpose of this patch is to know which URL consume the most
+bandwith, in average or in total.
+It may be interesting as well to know the standard deviation (ecart
+type in french) for some counters (like bytes_read).
+
+The results:
+- Sorting by average bytes read per URL:
+./halog -uba <~/tmp/haproxy.log | column -t | head
+2246 lines in, 302 lines out, 194 parsing errors
+18    0    5101     283    5101   283    126573  2278327  /lib/exe/js.php
+1     0    1        1      1      1      106734  106734   /wp-admin/images/screenshots/theme-customizer.png
+2     0    2        1      2      1      106511  213022   /wp-admin/css/wp-admin.css
+1     0    1        1      1      1      96698   96698    /wp-admin/images/screenshots/captions-1.png
+1     0    1        1      1      1      73165   73165    /wp-admin/images/screenshots/flex-header-1.png
+4     0    0        0      0      0      64832   259328   /cuisine/wp-content/plugins/stats/open-flash-chart.swf
+1     0    0        0      0      0      48647   48647    /wp-admin/images/screenshots/flex-header-3.png
+1     0    0        0      0      0      44046   44046    /wp-admin/images/screenshots/captions-2.png
+1     0    1        1      1      1      38830   38830    /wp-admin/images/screenshots/flex-header-2.png
+
+- Sorting by total bytes read per URL:
+./halog -ubt <~/tmp/haproxy.log | column -t | head
+2246 lines in, 302 lines out, 194 parsing errors
+18    0    5101     283    5101   283    126573  2278327  /lib/exe/js.php
+60    0    14387    239    14387  239    10081   604865   /lib/exe/css.php
+64    2    8820     137    8819   142    7742    495524   /doku.php
+14    0    250      17     250    17     24045   336632   /wp-admin/load-scripts.php
+71    0    6422     90     6422   90     4048    287419   /wp-admin/
+4     0    0        0      0      0      64832   259328   /cuisine/wp-content/plugins/stats/open-flash-chart.swf
+2     0    2        1      2      1      106511  213022   /wp-admin/css/wp-admin.css
+31    3    5423     174    5040   180    6804    210931   /index
+10    0    429      42     429    42     18009   180093   /cuisine/files/2011/10/tarte_figue_amande-e1318281546905-225x300.jpg
+(cherry picked from commit 61aaad06e85ae7f46cf5589bce8bc7f9331e7962)
+---
+ contrib/halog/halog.c |   39 ++++++++++++++++++++++++++++++++-------
+ 1 files changed, 32 insertions(+), 7 deletions(-)
+
+diff --git a/contrib/halog/halog.c b/contrib/halog/halog.c
+index f19be0b..274b7f3 100644
+--- a/contrib/halog/halog.c
++++ b/contrib/halog/halog.c
+@@ -29,6 +29,7 @@
+ #define SERVER_FIELD 8
+ #define TIME_FIELD 9
+ #define STATUS_FIELD 10
++#define BYTES_SENT_FIELD 11
+ #define TERM_CODES_FIELD 14
+ #define CONN_FIELD 15
+ #define QUEUE_LEN_FIELD 16
+@@ -67,6 +68,7 @@ struct url_stat {
+       char *url;
+       unsigned long long total_time;    /* sum(all reqs' times) */
+       unsigned long long total_time_ok; /* sum(all OK reqs' times) */
++      unsigned long long total_bytes_sent; /* sum(all bytes sent) */
+       unsigned int nb_err, nb_req;
+ };
+@@ -94,8 +96,6 @@ struct url_stat {
+ #define FILT_COUNT_URL_TAVG  0x040000
+ #define FILT_COUNT_URL_TTOTO 0x080000
+ #define FILT_COUNT_URL_TAVGO 0x100000
+-#define FILT_COUNT_URL_ANY   (FILT_COUNT_URL_ONLY|FILT_COUNT_URL_COUNT|FILT_COUNT_URL_ERR| \
+-                            FILT_COUNT_URL_TTOT|FILT_COUNT_URL_TAVG|FILT_COUNT_URL_TTOTO|FILT_COUNT_URL_TAVGO)
+ #define FILT_HTTP_ONLY       0x200000
+ #define FILT_TERM_CODE_NAME  0x400000
+@@ -106,6 +106,13 @@ struct url_stat {
+ #define FILT_QUEUE_ONLY            0x4000000
+ #define FILT_QUEUE_SRV_ONLY        0x8000000
++#define FILT_COUNT_URL_BAVG       0x10000000
++#define FILT_COUNT_URL_BTOT       0x20000000
++
++#define FILT_COUNT_URL_ANY   (FILT_COUNT_URL_ONLY|FILT_COUNT_URL_COUNT|FILT_COUNT_URL_ERR| \
++                            FILT_COUNT_URL_TTOT|FILT_COUNT_URL_TAVG|FILT_COUNT_URL_TTOTO|FILT_COUNT_URL_TAVGO| \
++                            FILT_COUNT_URL_BAVG|FILT_COUNT_URL_BTOT)
++
+ unsigned int filter = 0;
+ unsigned int filter_invert = 0;
+ const char *line;
+@@ -128,9 +135,10 @@ void usage(FILE *output, const char *msg)
+       fprintf(output,
+               "%s"
+               "Usage: halog [-h|--help] for long help\n"
+-              "       halog [-q] [-c] [-v] {-gt|-pct|-st|-tc|-srv|-u|-uc|-ue|-ua|-ut|-uao|-uto}\n"
++              "       halog [-q] [-c]\n"
++              "       {-gt|-pct|-st|-tc|-srv|-u|-uc|-ue|-ua|-ut|-uao|-uto|-uba|-ubt}\n"
+               "       [-s <skip>] [-e|-E] [-H] [-rt|-RT <time>] [-ad <delay>] [-ac <count>]\n"
+-              "       [-Q|-QS] [-tcn|-TCN <termcode>] [ -hs|-HS [min][:[max]] ] < log\n"
++              "       [-v] [-Q|-QS] [-tcn|-TCN <termcode>] [ -hs|-HS [min][:[max]] ] < log\n"
+               "\n",
+               msg ? msg : ""
+               );
+@@ -171,6 +179,7 @@ void help()
+              "       -u : by URL, -uc : request count, -ue : error count\n"
+              "       -ua : average response time, -uto : average total time\n"
+              "       -uao, -uto: average times computed on valid ('OK') requests\n"
++             "       -uba, -ubt: average bytes returned, total bytes returned\n"
+              );
+       exit(0);
+ }
+@@ -632,6 +641,10 @@ int main(int argc, char **argv)
+                       filter |= FILT_COUNT_URL_TAVGO;
+               else if (strcmp(argv[0], "-uto") == 0)
+                       filter |= FILT_COUNT_URL_TTOTO;
++              else if (strcmp(argv[0], "-uba") == 0)
++                      filter |= FILT_COUNT_URL_BAVG;
++              else if (strcmp(argv[0], "-ubt") == 0)
++                      filter |= FILT_COUNT_URL_BTOT;
+               else if (strcmp(argv[0], "-o") == 0) {
+                       if (output_file)
+                               die("Fatal: output file name already specified.\n");
+@@ -1029,6 +1042,10 @@ int main(int argc, char **argv)
+                                       ustat->node.val.key = ustat->total_time_ok;
+                               else if (filter & FILT_COUNT_URL_TAVGO)
+                                       ustat->node.val.key = (ustat->nb_req - ustat->nb_err) ? ustat->total_time_ok / (ustat->nb_req - ustat->nb_err) : 0;
++                              else if (filter & FILT_COUNT_URL_BAVG)
++                                      ustat->node.val.key = ustat->nb_req ? ustat->total_bytes_sent / ustat->nb_req : 0;
++                              else if (filter & FILT_COUNT_URL_BTOT)
++                                      ustat->node.val.key = ustat->total_bytes_sent;
+                               else
+                                       ustat->node.val.key = 0;
+@@ -1038,19 +1055,21 @@ int main(int argc, char **argv)
+                       timers[0] = timers[1];
+               }
+-              printf("#req err ttot tavg oktot okavg url\n");
++              printf("#req err ttot tavg oktot okavg bavg btot url\n");
+               /* scan the tree in its reverse sorting order */
+               node = eb_last(&timers[0]);
+               while (node) {
+                       ustat = container_of(node, struct url_stat, node.url.node);
+-                      printf("%d %d %Ld %Ld %Ld %Ld %s\n",
++                      printf("%d %d %Ld %Ld %Ld %Ld %Ld %Ld %s\n",
+                              ustat->nb_req,
+                              ustat->nb_err,
+                              ustat->total_time,
+                              ustat->nb_req ? ustat->total_time / ustat->nb_req : 0,
+                              ustat->total_time_ok,
+                              (ustat->nb_req - ustat->nb_err) ? ustat->total_time_ok / (ustat->nb_req - ustat->nb_err) : 0,
++                             ustat->nb_req ? ustat->total_bytes_sent / ustat->nb_req : 0,
++                             ustat->total_bytes_sent,
+                              ustat->url);
+                       node = eb_prev(node);
+@@ -1233,6 +1252,7 @@ void filter_count_url(const char *accept_field, const char *time_field, struct t
+       struct ebpt_node *ebpt_old;
+       const char *b, *e;
+       int f, err, array[5];
++      int val;
+       /* let's collect the response time */
+       if (!time_field) {
+@@ -1276,12 +1296,16 @@ void filter_count_url(const char *accept_field, const char *time_field, struct t
+       ustat->total_time = (array[3] >= 0) ? array[3] : array[4];
+       ustat->total_time_ok = (array[3] >= 0) ? array[3] : 0;
++      e = field_start(e, BYTES_SENT_FIELD - TIME_FIELD + 1);
++      val = str2ic(e);
++      ustat->total_bytes_sent = val;
++
+       /* the line may be truncated because of a bad request or anything like this,
+        * without a method. Also, if it does not begin with an quote, let's skip to
+        * the next field because it's a capture. Let's fall back to the "method" itself
+        * if there's nothing else.
+        */
+-      e = field_start(e, METH_FIELD - TIME_FIELD + 1); // avg 100 ns per line
++      e = field_start(e, METH_FIELD - BYTES_SENT_FIELD + 1);
+       while (*e != '"' && *e) {
+               /* Note: some syslog servers escape quotes ! */
+               if (*e == '\\' && e[1] == '"')
+@@ -1324,6 +1348,7 @@ void filter_count_url(const char *accept_field, const char *time_field, struct t
+               ustat_old->nb_err += ustat->nb_err;
+               ustat_old->total_time += ustat->total_time;
+               ustat_old->total_time_ok += ustat->total_time_ok;
++              ustat_old->total_bytes_sent += ustat->total_bytes_sent;
+       } else {
+               ustat->url = ustat->node.url.key = strdup(ustat->node.url.key);
+               ustat = NULL; /* node was used */
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0004-MINOR-halog-sort-output-by-cookie-code-1.4.22.diff b/net/haproxy/patches/0004-MINOR-halog-sort-output-by-cookie-code-1.4.22.diff
new file mode 100644 (file)
index 0000000..72b48fd
--- /dev/null
@@ -0,0 +1,118 @@
+From b4d12bdacf6ff4cc96abaffb8c3e801f94a84de2 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Wed, 10 Oct 2012 10:26:22 +0200
+Subject: MINOR: halog: sort output by cookie code
+
+It's sometimes useful to have the output sorted by cookie code to see
+the ratios of NI vs VN for example. This is now possible with -cc.
+(cherry picked from commit 8a09b663a829f7012c50743adaf3d29cc81700c5)
+---
+ contrib/halog/halog.c |   36 +++++++++++++++++++++++++++++++++---
+ 1 files changed, 33 insertions(+), 3 deletions(-)
+
+diff --git a/contrib/halog/halog.c b/contrib/halog/halog.c
+index 274b7f3..e4d62e9 100644
+--- a/contrib/halog/halog.c
++++ b/contrib/halog/halog.c
+@@ -1,7 +1,7 @@
+ /*
+  * haproxy log statistics reporter
+  *
+- * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
++ * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+@@ -113,6 +113,8 @@ struct url_stat {
+                             FILT_COUNT_URL_TTOT|FILT_COUNT_URL_TAVG|FILT_COUNT_URL_TTOTO|FILT_COUNT_URL_TAVGO| \
+                             FILT_COUNT_URL_BAVG|FILT_COUNT_URL_BTOT)
++#define FILT_COUNT_COOK_CODES 0x40000000
++
+ unsigned int filter = 0;
+ unsigned int filter_invert = 0;
+ const char *line;
+@@ -124,6 +126,7 @@ const char *fgets2(FILE *stream);
+ void filter_count_url(const char *accept_field, const char *time_field, struct timer **tptr);
+ void filter_count_srv_status(const char *accept_field, const char *time_field, struct timer **tptr);
++void filter_count_cook_codes(const char *accept_field, const char *time_field, struct timer **tptr);
+ void filter_count_term_codes(const char *accept_field, const char *time_field, struct timer **tptr);
+ void filter_count_status(const char *accept_field, const char *time_field, struct timer **tptr);
+ void filter_graphs(const char *accept_field, const char *time_field, struct timer **tptr);
+@@ -136,7 +139,7 @@ void usage(FILE *output, const char *msg)
+               "%s"
+               "Usage: halog [-h|--help] for long help\n"
+               "       halog [-q] [-c]\n"
+-              "       {-gt|-pct|-st|-tc|-srv|-u|-uc|-ue|-ua|-ut|-uao|-uto|-uba|-ubt}\n"
++              "       {-cc|-gt|-pct|-st|-tc|-srv|-u|-uc|-ue|-ua|-ut|-uao|-uto|-uba|-ubt}\n"
+               "       [-s <skip>] [-e|-E] [-H] [-rt|-RT <time>] [-ad <delay>] [-ac <count>]\n"
+               "       [-v] [-Q|-QS] [-tcn|-TCN <termcode>] [ -hs|-HS [min][:[max]] ] < log\n"
+               "\n",
+@@ -172,6 +175,7 @@ void help()
+              " -c    only report the number of lines that would have been printed\n"
+              " -pct  output connect and response times percentiles\n"
+              " -st   output number of requests per HTTP status code\n"
++             " -cc   output number of requests per cookie code (2 chars)\n"
+              " -tc   output number of requests per termination code (2 chars)\n"
+              " -srv  output statistics per server (time, requests, errors)\n"
+              " -u*   output statistics per URL (time, requests, errors)\n"
+@@ -595,6 +599,8 @@ int main(int argc, char **argv)
+                       filter |= FILT_COUNT_STATUS;
+               else if (strcmp(argv[0], "-srv") == 0)
+                       filter |= FILT_COUNT_SRV_STATUS;
++              else if (strcmp(argv[0], "-cc") == 0)
++                      filter |= FILT_COUNT_COOK_CODES;
+               else if (strcmp(argv[0], "-tc") == 0)
+                       filter |= FILT_COUNT_TERM_CODES;
+               else if (strcmp(argv[0], "-tcn") == 0) {
+@@ -676,6 +682,8 @@ int main(int argc, char **argv)
+               line_filter = filter_graphs;
+       else if (filter & FILT_COUNT_STATUS)
+               line_filter = filter_count_status;
++      else if (filter & FILT_COUNT_COOK_CODES)
++              line_filter = filter_count_cook_codes;
+       else if (filter & FILT_COUNT_TERM_CODES)
+               line_filter = filter_count_term_codes;
+       else if (filter & FILT_COUNT_SRV_STATUS)
+@@ -1005,7 +1013,7 @@ int main(int argc, char **argv)
+                       lines_out++;
+               }
+       }
+-      else if (filter & FILT_COUNT_TERM_CODES) {
++      else if (filter & (FILT_COUNT_TERM_CODES|FILT_COUNT_COOK_CODES)) {
+               /* output all statuses in the form of <code> <occurrences> */
+               n = eb32_first(&timers[0]);
+               while (n) {
+@@ -1129,6 +1137,28 @@ void filter_count_status(const char *accept_field, const char *time_field, struc
+       t2->count++;
+ }
++void filter_count_cook_codes(const char *accept_field, const char *time_field, struct timer **tptr)
++{
++      struct timer *t2;
++      const char *b;
++      int val;
++
++      if (time_field)
++              b = field_start(time_field, TERM_CODES_FIELD - TIME_FIELD + 1);
++      else
++              b = field_start(accept_field, TERM_CODES_FIELD - ACCEPT_FIELD + 1);
++
++      if (unlikely(!*b)) {
++              truncated_line(linenum, line);
++              return;
++      }
++
++      val = 256 * b[2] + b[3];
++
++      t2 = insert_value(&timers[0], tptr, val);
++      t2->count++;
++}
++
+ void filter_count_term_codes(const char *accept_field, const char *time_field, struct timer **tptr)
+ {
+       struct timer *t2;
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0005-BUG-MINOR-halog-ad-ac-report-the-correct-numbe-1.4.22.diff b/net/haproxy/patches/0005-BUG-MINOR-halog-ad-ac-report-the-correct-numbe-1.4.22.diff
new file mode 100644 (file)
index 0000000..c76d569
--- /dev/null
@@ -0,0 +1,29 @@
+From 113e6626ca26de31e2523a5b197a5bac4ca73dcc Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Wed, 10 Oct 2012 13:41:52 +0200
+Subject: BUG/MINOR: halog: -ad/-ac report the correct number of output lines
+
+There was a lines_out++ left from earlier code, causing each input
+line to be counted as an output line.
+
+This fix also affects 1.4 and should be backported.
+(cherry picked from commit 0a706880160167f872247723c6a041eb31a20c29)
+---
+ contrib/halog/halog.c |    1 -
+ 1 files changed, 0 insertions(+), 1 deletions(-)
+
+diff --git a/contrib/halog/halog.c b/contrib/halog/halog.c
+index e4d62e9..8f7f04a 100644
+--- a/contrib/halog/halog.c
++++ b/contrib/halog/halog.c
+@@ -1111,7 +1111,6 @@ void filter_accept_holes(const char *accept_field, const char *time_field, struc
+       t2 = insert_value(&timers[0], tptr, val);
+       t2->count++;
+-      lines_out++;
+       return;
+ }
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0006-BUG-MINOR-halog-fix-help-message-for-ut-uto-1.4.22.diff b/net/haproxy/patches/0006-BUG-MINOR-halog-fix-help-message-for-ut-uto-1.4.22.diff
new file mode 100644 (file)
index 0000000..473b2b8
--- /dev/null
@@ -0,0 +1,27 @@
+From 1fd5d70b52a1d3b3f12e577cc158d0988e103f0d Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Wed, 10 Oct 2012 14:57:35 +0200
+Subject: BUG/MINOR: halog: fix help message for -ut/-uto
+
+Erroneous copy-paste suggesting wrong option.
+(cherry picked from commit 4201df77df34492be89e9c720397ff66bc5775d9)
+---
+ contrib/halog/halog.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/contrib/halog/halog.c b/contrib/halog/halog.c
+index 8f7f04a..4e3cfc4 100644
+--- a/contrib/halog/halog.c
++++ b/contrib/halog/halog.c
+@@ -181,7 +181,7 @@ void help()
+              " -u*   output statistics per URL (time, requests, errors)\n"
+              "       Additional characters indicate the output sorting key :\n"
+              "       -u : by URL, -uc : request count, -ue : error count\n"
+-             "       -ua : average response time, -uto : average total time\n"
++             "       -ua : average response time, -ut : average total time\n"
+              "       -uao, -uto: average times computed on valid ('OK') requests\n"
+              "       -uba, -ubt: average bytes returned, total bytes returned\n"
+              );
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0007-BUG-MEDIUM-http-set-DONTWAIT-on-data-when-swit-1.4.22.diff b/net/haproxy/patches/0007-BUG-MEDIUM-http-set-DONTWAIT-on-data-when-swit-1.4.22.diff
new file mode 100644 (file)
index 0000000..ad66045
--- /dev/null
@@ -0,0 +1,75 @@
+From 7a883f8542dffb7299a903eb9a82fed3980337fa Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sat, 20 Oct 2012 10:38:09 +0200
+Subject: BUG/MEDIUM: http: set DONTWAIT on data when switching to tunnel mode
+
+Jaroslaw Bojar diagnosed an issue when haproxy switches to tunnel mode
+after a transfer. The response data are sent with the MSG_MORE flag,
+causing them to be needlessly queued in the kernel. In order to fix this,
+we set the CF_NEVER_WAIT flag on the channels when switching to tunnel
+mode.
+
+One issue remained with client-side keep-alive : if the response is sent
+before the end of the request, it suffers the same issue for the same
+reason. This is easily addressed by setting the CF_SEND_DONTWAIT flag
+on the channel when the response has been parsed and we're waiting for
+the other side.
+
+The same issue is present in 1.4 so the fix must be backported.
+(cherry picked from commit fc47f91c9cc66e3652d98deab82d6e5fe3a59711)
+---
+ src/proto_http.c |   10 ++++++++++
+ 1 files changed, 10 insertions(+), 0 deletions(-)
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index dc65cbd..2ba38f1 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -4178,6 +4178,7 @@ int http_sync_req_state(struct session *s)
+                       /* if any side switches to tunnel mode, the other one does too */
+                       buffer_auto_read(buf);
+                       txn->req.msg_state = HTTP_MSG_TUNNEL;
++                      buf->flags |= BF_NEVER_WAIT;
+                       goto wait_other_side;
+               }
+@@ -4211,6 +4212,7 @@ int http_sync_req_state(struct session *s)
+                        */
+                       buffer_auto_read(buf);
+                       txn->req.msg_state = HTTP_MSG_TUNNEL;
++                      buf->flags |= BF_NEVER_WAIT;
+               }
+               if (buf->flags & (BF_SHUTW|BF_SHUTW_NOW)) {
+@@ -4297,6 +4299,7 @@ int http_sync_res_state(struct session *s)
+                       /* if any side switches to tunnel mode, the other one does too */
+                       buffer_auto_read(buf);
+                       txn->rsp.msg_state = HTTP_MSG_TUNNEL;
++                      buf->flags |= BF_NEVER_WAIT;
+                       goto wait_other_side;
+               }
+@@ -4334,6 +4337,7 @@ int http_sync_res_state(struct session *s)
+                        */
+                       buffer_auto_read(buf);
+                       txn->rsp.msg_state = HTTP_MSG_TUNNEL;
++                      buf->flags |= BF_NEVER_WAIT;
+               }
+               if (buf->flags & (BF_SHUTW|BF_SHUTW_NOW)) {
+@@ -4379,6 +4383,12 @@ int http_sync_res_state(struct session *s)
+  wait_other_side:
+       http_silent_debug(__LINE__, s);
++
++      /* We force the response to leave immediately if we're waiting for the
++       * other side, since there is no pending shutdown to push it out.
++       */
++      if (!(buf->flags & BF_OUT_EMPTY))
++              buf->flags |= BF_SEND_DONTWAIT;
+       return txn->rsp.msg_state != old_state || buf->flags != old_flags;
+ }
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0008-BUG-MEDIUM-command-line-option-D-must-have-pre-1.4.22.diff b/net/haproxy/patches/0008-BUG-MEDIUM-command-line-option-D-must-have-pre-1.4.22.diff
new file mode 100644 (file)
index 0000000..4203404
--- /dev/null
@@ -0,0 +1,42 @@
+From ce64f84c174fc65ea02f3f1cba2b3295c0b34198 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Fri, 26 Oct 2012 16:04:28 +0200
+Subject: BUG/MEDIUM: command-line option -D must have precedence over "debug"
+
+From the beginning it has been said that -D must always be used on the
+command line from startup scripts so that haproxy does not accidentally
+stay in foreground when loaded from init script... Except that this has
+not been true for a long time now.
+
+The fix is easy and must be backported to 1.4 too which is affected.
+(cherry picked from commit 772f0dd545eb3837e2bc794f4c4863663be3742c)
+---
+ src/haproxy.c |   11 +++++++++--
+ 1 files changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/src/haproxy.c b/src/haproxy.c
+index 2944462..ec481aa 100644
+--- a/src/haproxy.c
++++ b/src/haproxy.c
+@@ -649,9 +649,16 @@ void init(int argc, char **argv)
+       if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
+               /* command line debug mode inhibits configuration mode */
+               global.mode &= ~(MODE_DAEMON | MODE_QUIET);
++              global.mode |= (arg_mode & (MODE_DEBUG | MODE_FOREGROUND));
+       }
+-      global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
+-                                  MODE_VERBOSE | MODE_DEBUG ));
++
++      if (arg_mode & MODE_DAEMON) {
++              /* command line daemon mode inhibits foreground and debug modes mode */
++              global.mode &= ~(MODE_DEBUG | MODE_FOREGROUND);
++              global.mode |= (arg_mode & MODE_DAEMON);
++      }
++
++      global.mode |= (arg_mode & (MODE_QUIET | MODE_VERBOSE));
+       if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
+               Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0009-BUG-fix-garbage-data-when-http-send-name-heade-1.4.22.diff b/net/haproxy/patches/0009-BUG-fix-garbage-data-when-http-send-name-heade-1.4.22.diff
new file mode 100644 (file)
index 0000000..47c4196
--- /dev/null
@@ -0,0 +1,49 @@
+From 5b4d0775f0afd10c80e63842dca85a69281c9433 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Cyril=20Bont=C3=A9?= <cyril.bonte@free.fr>
+Date: Thu, 1 Nov 2012 18:48:23 +0100
+Subject: BUG: fix garbage data when http-send-name-header replaces an existing header
+
+This patch is an attempt to prevent sending garbage data when
+http-send-name-header replaced existing headers in the request.
+
+http-send-name-header is applied late in the request processing. The buffer is
+already ready to be sent to the backend server. When headers are removed, the
+data length is not modified, resulting in sending more data than required. By
+reducing the data length to send after removing them, this should fix the
+issue.
+
+This patch doesn't need to be ported to haproxy-1.5, which already readjust the
+amount of data to be forwarded.
+
+This issue was reported by Michael Seiferle at BaseX, who also tested and
+confirmed the fix.
+---
+ src/proto_http.c |    5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index 2ba38f1..1ad838b 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -3981,6 +3981,7 @@ int http_send_name_header(struct http_txn *txn, struct http_msg *msg, struct buf
+       char *hdr_val;
++      int delta = txn->req.eoh;
+       while (http_find_header2(hdr_name, hdr_name_len, msg->sol, &txn->hdr_idx, &ctx)) {
+               /* remove any existing values from the header */
+               http_remove_header2(msg, buf, &txn->hdr_idx, &ctx);
+@@ -3994,6 +3995,10 @@ int http_send_name_header(struct http_txn *txn, struct http_msg *msg, struct buf
+       *hdr_val++ = ' ';
+       hdr_val += strlcpy2(hdr_val, srv_name, trash + trashlen - hdr_val);
+       http_header_add_tail2(buf, msg, &txn->hdr_idx, trash, hdr_val - trash);
++      delta -= txn->req.eoh;
++
++      /* Adjust buffer data length to send */
++      buf->send_max -= delta;
+       return 0;
+ }
+-- 
+1.7.1
+
index 26906d41dba2c296e5cf42e084bc5694025f2db1..340f54b45979d72eba0e85193d911e7d9bda1a0f 100644 (file)
@@ -1,6 +1,6 @@
 --- a/doc/configuration.txt
 +++ b/doc/configuration.txt
-@@ -1337,6 +1337,7 @@ bind [<address>]:<port_range> [, ...] tr
+@@ -1339,6 +1339,7 @@ bind [<address>]:<port_range> [, ...] tr
  bind [<address>]:<port_range> [, ...] id <id>
  bind [<address>]:<port_range> [, ...] name <name>
  bind [<address>]:<port_range> [, ...] defer-accept
@@ -8,7 +8,7 @@
    Define one or several listening addresses and/or ports in a frontend.
    May be used in sections :   defaults | frontend | listen | backend
                                    no   |    yes   |   yes  |   no
-@@ -1417,6 +1418,19 @@ bind [<address>]:<port_range> [, ...] de
+@@ -1419,6 +1420,19 @@ bind [<address>]:<port_range> [, ...] de
                    with front firewalls which would see an established
                    connection while the proxy will only see it in SYN_RECV.
  
@@ -28,7 +28,7 @@
    It is possible to specify a list of address:port combinations delimited by
    commas. The frontend will then listen on all of these addresses. There is no
    fixed limit to the number of addresses and ports which can be listened on in
-@@ -1427,8 +1441,10 @@ bind [<address>]:<port_range> [, ...] de
+@@ -1429,8 +1443,10 @@ bind [<address>]:<port_range> [, ...] de
          listen http_proxy
              bind :80,:443
              bind 10.0.0.1:10080,10.0.0.1:10443
@@ -40,7 +40,7 @@
  
  
  bind-process [ all | odd | even | <number 1-32> ] ...
-@@ -7215,7 +7231,9 @@ marked with a star ('*') after the field
+@@ -7231,7 +7247,9 @@ marked with a star ('*') after the field
  
  Detailed fields description :
    - "client_ip" is the IP address of the client which initiated the TCP
@@ -51,7 +51,7 @@
  
    - "client_port" is the TCP port of the client which initiated the connection.
  
-@@ -7388,7 +7406,9 @@ with a star ('*') after the field name b
+@@ -7404,7 +7422,9 @@ with a star ('*') after the field name b
  
  Detailed fields description :
    - "client_ip" is the IP address of the client which initiated the TCP
   * socket. The listener provides the protocol-specific accept() function to
 --- a/src/cfgparse.c
 +++ b/src/cfgparse.c
-@@ -1466,6 +1466,16 @@ int cfg_parse_listen(const char *file, i
+@@ -1467,6 +1467,16 @@ int cfg_parse_listen(const char *file, i
  #endif
                        }
  
                        if (!strcmp(args[cur_arg], "name")) {
                                struct listener *l;
  
-@@ -1518,7 +1528,7 @@ int cfg_parse_listen(const char *file, i
+@@ -1519,7 +1529,7 @@ int cfg_parse_listen(const char *file, i
                                continue;
                        }
  
                              file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
-@@ -5731,6 +5741,9 @@ out_uri_auth_compat:
+@@ -5732,6 +5742,9 @@ out_uri_auth_compat:
                        listener->handler = process_session;
                        listener->analysers |= curproxy->fe_req_ana;
  
   */
 --- a/src/proto_http.c
 +++ b/src/proto_http.c
-@@ -4087,7 +4087,8 @@ void http_end_txn_clean_session(struct s
+@@ -4127,7 +4127,8 @@ void http_end_txn_clean_session(struct s
        if (s->rep->lr >= s->rep->data + s->rep->size)
                s->rep->lr -= s->req->size;
  
        s->rep->analysers = 0;
  
        http_silent_debug(__LINE__, s);
-@@ -7624,7 +7625,6 @@ void http_reset_txn(struct session *s)
+@@ -7670,7 +7671,6 @@ void http_reset_txn(struct session *s)
        http_init_txn(s);
  
        s->be = s->fe;
diff --git a/net/haproxy/patches/0010-OPTIM-halog-keep-a-fast-path-for-the-lines-cou-1.4.22.diff b/net/haproxy/patches/0010-OPTIM-halog-keep-a-fast-path-for-the-lines-cou-1.4.22.diff
new file mode 100644 (file)
index 0000000..dcab974
--- /dev/null
@@ -0,0 +1,54 @@
+From c998e6347e6e6940263157fb341a8444d789aa5f Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 3 Jan 2012 09:23:03 +0100
+Subject: OPTIM: halog: keep a fast path for the lines-count only
+
+[ note: this backport is not absolutely required for 1.4 but it eases
+  further backports ]
+
+Using "halog -c" is still something quite common to perform on logs,
+but unfortunately since the recent added controls, it was sensibly
+slowed down due to the parsing of the accept date field.
+
+Now we use a specific loop for the case where nothing is needed from
+the input, and this sped up the line counting by 2.5x. A 2.4 GHz Xeon
+now counts lines at a rate of 2 GB of logs per second.
+
+(cherry picked from commit e1a908c369ab988448c6672066ad1d09b6919d02)
+---
+ contrib/halog/halog.c |   12 +++++++++++-
+ 1 files changed, 11 insertions(+), 1 deletions(-)
+
+diff --git a/contrib/halog/halog.c b/contrib/halog/halog.c
+index 4e3cfc4..3912807 100644
+--- a/contrib/halog/halog.c
++++ b/contrib/halog/halog.c
+@@ -702,6 +702,16 @@ int main(int argc, char **argv)
+       posix_fadvise(0, 0, 0, POSIX_FADV_SEQUENTIAL);
+ #endif
++      if (!line_filter &&
++          !(filter & (FILT_HTTP_ONLY|FILT_TIME_RESP|FILT_ERRORS_ONLY|FILT_HTTP_STATUS|FILT_QUEUE_ONLY|FILT_QUEUE_SRV_ONLY|FILT_TERM_CODE_NAME))) {
++              /* read the whole file at once first */
++              if (!filter_invert)
++                      while (fgets2(stdin) != NULL)
++                              lines_out++;
++
++              goto skip_filters;
++      }
++
+       while ((line = fgets2(stdin)) != NULL) {
+               linenum++;
+               time_field = NULL; accept_field = NULL;
+@@ -859,7 +869,7 @@ int main(int argc, char **argv)
+                       lines_out++; /* we're just counting lines */
+       }
+-
++ skip_filters:
+       /*****************************************************
+        * Here we've finished reading all input. Depending on the
+        * filters, we may still have some analysis to run on the
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0011-MINOR-halog-add-a-parameter-to-limit-output-li-1.4.22.diff b/net/haproxy/patches/0011-MINOR-halog-add-a-parameter-to-limit-output-li-1.4.22.diff
new file mode 100644 (file)
index 0000000..d1bb4d8
--- /dev/null
@@ -0,0 +1,134 @@
+From 9f03ab8e3ec603f2aed944a7887bcdf7be52009a Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Wed, 10 Oct 2012 16:49:28 +0200
+Subject: MINOR: halog: add a parameter to limit output line count
+
+Sometimes it's useful to limit the output to a number of lines, for
+example when output is already sorted (eg: 10 slowest URLs, ...). Now
+we can use -m for this.
+(cherry picked from commit 667c905fe5153a8754bd8177c80dd9e6c245a0b0)
+[ this patch introduces a but that is fixed by commit a1629a59 ]
+---
+ contrib/halog/halog.c |   28 ++++++++++++++++++++++++----
+ 1 files changed, 24 insertions(+), 4 deletions(-)
+
+diff --git a/contrib/halog/halog.c b/contrib/halog/halog.c
+index 3912807..7e16cd5 100644
+--- a/contrib/halog/halog.c
++++ b/contrib/halog/halog.c
+@@ -121,6 +121,7 @@ const char *line;
+ int linenum = 0;
+ int parse_err = 0;
+ int lines_out = 0;
++int lines_max = -1;
+ const char *fgets2(FILE *stream);
+@@ -138,7 +139,7 @@ void usage(FILE *output, const char *msg)
+       fprintf(output,
+               "%s"
+               "Usage: halog [-h|--help] for long help\n"
+-              "       halog [-q] [-c]\n"
++              "       halog [-q] [-c] [-m <lines>]\n"
+               "       {-cc|-gt|-pct|-st|-tc|-srv|-u|-uc|-ue|-ua|-ut|-uao|-uto|-uba|-ubt}\n"
+               "       [-s <skip>] [-e|-E] [-H] [-rt|-RT <time>] [-ad <delay>] [-ac <count>]\n"
+               "       [-v] [-Q|-QS] [-tcn|-TCN <termcode>] [ -hs|-HS [min][:[max]] ] < log\n"
+@@ -170,7 +171,7 @@ void help()
+              "Modifiers\n"
+              " -v                      invert the input filtering condition\n"
+              " -q                      don't report errors/warnings\n"
+-             "\n"
++             " -m <lines>              limit output to the first <lines> lines\n"
+              "Output filters - only one may be used at a time\n"
+              " -c    only report the number of lines that would have been printed\n"
+              " -pct  output connect and response times percentiles\n"
+@@ -575,6 +576,11 @@ int main(int argc, char **argv)
+                       argc--; argv++;
+                       skip_fields = atol(*argv);
+               }
++              else if (strcmp(argv[0], "-m") == 0) {
++                      if (argc < 2) die("missing option for -m");
++                      argc--; argv++;
++                      lines_max = atol(*argv);
++              }
+               else if (strcmp(argv[0], "-e") == 0)
+                       filter |= FILT_ERRORS_ONLY;
+               else if (strcmp(argv[0], "-E") == 0)
+@@ -702,7 +708,7 @@ int main(int argc, char **argv)
+       posix_fadvise(0, 0, 0, POSIX_FADV_SEQUENTIAL);
+ #endif
+-      if (!line_filter &&
++      if (!line_filter && lines_max >= 0 &&
+           !(filter & (FILT_HTTP_ONLY|FILT_TIME_RESP|FILT_ERRORS_ONLY|FILT_HTTP_STATUS|FILT_QUEUE_ONLY|FILT_QUEUE_SRV_ONLY|FILT_TERM_CODE_NAME))) {
+               /* read the whole file at once first */
+               if (!filter_invert)
+@@ -867,6 +873,8 @@ int main(int argc, char **argv)
+                       line_filter(accept_field, time_field, &t);
+               else
+                       lines_out++; /* we're just counting lines */
++              if (lines_out >= lines_max)
++                      break;
+       }
+  skip_filters:
+@@ -904,8 +912,10 @@ int main(int argc, char **argv)
+                               ms = h % 1000; h = h / 1000;
+                               s = h % 60; h = h / 60;
+                               m = h % 60; h = h / 60;
+-                              lines_out++;
+                               printf("%02d:%02d:%02d.%03d %d %d %d\n", h, m, s, ms, last, d, t->count);
++                              lines_out++;
++                              if (lines_out >= lines_max)
++                                      break;
+                       }
+                       n = eb32_next(n);
+               }
+@@ -937,6 +947,8 @@ int main(int argc, char **argv)
+                               if (d > 0.0) {
+                                       printf("%d %d %f\n", f, last, d+1.0);
+                                       lines_out++;
++                                      if (lines_out >= lines_max)
++                                              break;
+                               }
+                               n = eb32_next(n);
+@@ -994,6 +1006,8 @@ int main(int argc, char **argv)
+                       t = container_of(n, struct timer, node);
+                       printf("%d %d\n", n->key, t->count);
+                       lines_out++;
++                      if (lines_out >= lines_max)
++                              break;
+                       n = eb32_next(n);
+               }
+       }
+@@ -1021,6 +1035,8 @@ int main(int argc, char **argv)
+                              (int)(srv->cum_ct / (srv->nb_ct?srv->nb_ct:1)), (int)(srv->cum_rt / (srv->nb_rt?srv->nb_rt:1)));
+                       srv_node = ebmb_next(srv_node);
+                       lines_out++;
++                      if (lines_out >= lines_max)
++                              break;
+               }
+       }
+       else if (filter & (FILT_COUNT_TERM_CODES|FILT_COUNT_COOK_CODES)) {
+@@ -1030,6 +1046,8 @@ int main(int argc, char **argv)
+                       t = container_of(n, struct timer, node);
+                       printf("%c%c %d\n", (n->key >> 8), (n->key) & 255, t->count);
+                       lines_out++;
++                      if (lines_out >= lines_max)
++                              break;
+                       n = eb32_next(n);
+               }
+       }
+@@ -1092,6 +1110,8 @@ int main(int argc, char **argv)
+                       node = eb_prev(node);
+                       lines_out++;
++                      if (lines_out >= lines_max)
++                              break;
+               }
+       }
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0012-BUG-halog-fix-broken-output-limitation-1.4.22.diff b/net/haproxy/patches/0012-BUG-halog-fix-broken-output-limitation-1.4.22.diff
new file mode 100644 (file)
index 0000000..6318031
--- /dev/null
@@ -0,0 +1,110 @@
+From e1e14b5d2a0ff3097c93f4605f33b38df1e3e266 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 13 Nov 2012 20:48:15 +0100
+Subject: BUG: halog: fix broken output limitation
+
+Commit 667c905f introduced parameter -m to halog which limits the size
+of the output. Unfortunately it is completely broken in that it doesn't
+check that the limit was previously set or not, and also prevents a
+simple counting operation from returning anything if a limit is not set.
+
+Note that the -gt and -pct outputs behave differently in face of this
+limit, since they count the valid output lines BEFORE actually producing
+the data, so the limit really applies to valid input lines.
+(cherry picked from commit a1629a59d17208897622d4e0d8ecddf157d55074)
+---
+ contrib/halog/halog.c |   26 +++++++++++---------------
+ 1 files changed, 11 insertions(+), 15 deletions(-)
+
+diff --git a/contrib/halog/halog.c b/contrib/halog/halog.c
+index 7e16cd5..61034ec 100644
+--- a/contrib/halog/halog.c
++++ b/contrib/halog/halog.c
+@@ -708,11 +708,11 @@ int main(int argc, char **argv)
+       posix_fadvise(0, 0, 0, POSIX_FADV_SEQUENTIAL);
+ #endif
+-      if (!line_filter && lines_max >= 0 &&
++      if (!line_filter && /* FILT_COUNT_ONLY ( see above), and no input filter (see below) */
+           !(filter & (FILT_HTTP_ONLY|FILT_TIME_RESP|FILT_ERRORS_ONLY|FILT_HTTP_STATUS|FILT_QUEUE_ONLY|FILT_QUEUE_SRV_ONLY|FILT_TERM_CODE_NAME))) {
+-              /* read the whole file at once first */
++              /* read the whole file at once first, ignore it if inverted output */
+               if (!filter_invert)
+-                      while (fgets2(stdin) != NULL)
++                      while ((lines_max < 0 || lines_out < lines_max) && fgets2(stdin) != NULL)
+                               lines_out++;
+               goto skip_filters;
+@@ -872,8 +872,8 @@ int main(int argc, char **argv)
+               if (line_filter)
+                       line_filter(accept_field, time_field, &t);
+               else
+-                      lines_out++; /* we're just counting lines */
+-              if (lines_out >= lines_max)
++                      lines_out++; /* FILT_COUNT_ONLY was used, so we're just counting lines */
++              if (lines_max >= 0 && lines_out >= lines_max)
+                       break;
+       }
+@@ -914,7 +914,7 @@ int main(int argc, char **argv)
+                               m = h % 60; h = h / 60;
+                               printf("%02d:%02d:%02d.%03d %d %d %d\n", h, m, s, ms, last, d, t->count);
+                               lines_out++;
+-                              if (lines_out >= lines_max)
++                              if (lines_max >= 0 && lines_out >= lines_max)
+                                       break;
+                       }
+                       n = eb32_next(n);
+@@ -944,12 +944,8 @@ int main(int argc, char **argv)
+                               else
+                                       d = val;
+-                              if (d > 0.0) {
++                              if (d > 0.0)
+                                       printf("%d %d %f\n", f, last, d+1.0);
+-                                      lines_out++;
+-                                      if (lines_out >= lines_max)
+-                                              break;
+-                              }
+                               n = eb32_next(n);
+                       }
+@@ -1006,7 +1002,7 @@ int main(int argc, char **argv)
+                       t = container_of(n, struct timer, node);
+                       printf("%d %d\n", n->key, t->count);
+                       lines_out++;
+-                      if (lines_out >= lines_max)
++                      if (lines_max >= 0 && lines_out >= lines_max)
+                               break;
+                       n = eb32_next(n);
+               }
+@@ -1035,7 +1031,7 @@ int main(int argc, char **argv)
+                              (int)(srv->cum_ct / (srv->nb_ct?srv->nb_ct:1)), (int)(srv->cum_rt / (srv->nb_rt?srv->nb_rt:1)));
+                       srv_node = ebmb_next(srv_node);
+                       lines_out++;
+-                      if (lines_out >= lines_max)
++                      if (lines_max >= 0 && lines_out >= lines_max)
+                               break;
+               }
+       }
+@@ -1046,7 +1042,7 @@ int main(int argc, char **argv)
+                       t = container_of(n, struct timer, node);
+                       printf("%c%c %d\n", (n->key >> 8), (n->key) & 255, t->count);
+                       lines_out++;
+-                      if (lines_out >= lines_max)
++                      if (lines_max >= 0 && lines_out >= lines_max)
+                               break;
+                       n = eb32_next(n);
+               }
+@@ -1110,7 +1106,7 @@ int main(int argc, char **argv)
+                       node = eb_prev(node);
+                       lines_out++;
+-                      if (lines_out >= lines_max)
++                      if (lines_max >= 0 && lines_out >= lines_max)
+                               break;
+               }
+       }
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0013-MEDIUM-checks-avoid-accumulating-TIME_WAITs-du-1.4.22.diff b/net/haproxy/patches/0013-MEDIUM-checks-avoid-accumulating-TIME_WAITs-du-1.4.22.diff
new file mode 100644 (file)
index 0000000..7e9f067
--- /dev/null
@@ -0,0 +1,91 @@
+From 2f61455a647d9539a49392d475e7f2aeef7dcfce Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sat, 29 Dec 2012 22:23:02 +0100
+Subject: MEDIUM: checks: avoid accumulating TIME_WAITs during checks
+
+Some checks which do not induce a close from the server accumulate
+local TIME_WAIT sockets because they're cleanly shut down. Typically
+TCP probes cause this. This is very problematic when there are many
+servers, when the checks are fast or when local source ports are rare.
+
+So now we'll disable lingering on the socket instead of sending a
+shutdown. Before doing this we try to drain any possibly pending data.
+That way we avoid sending an RST when the server has closed first.
+
+This change means that some servers will see more RSTs, but this is
+needed to avoid local source port starvation.
+(cherry picked from commit fd29cc537b8511db6e256529ded625c8e7f856d0)
+---
+ src/checks.c |   22 +++++++++++++++++-----
+ 1 files changed, 17 insertions(+), 5 deletions(-)
+
+diff --git a/src/checks.c b/src/checks.c
+index 0aa65c0..3d01282 100644
+--- a/src/checks.c
++++ b/src/checks.c
+@@ -833,6 +833,10 @@ static int event_srv_chk_w(int fd)
+                       /* good TCP connection is enough */
+                       set_server_check_status(s, HCHK_STATUS_L4OK, NULL);
++
++                      /* avoid accumulating TIME_WAIT on connect-only checks */
++                      setsockopt(fd, SOL_SOCKET, SO_LINGER,
++                                 (struct linger *) &nolinger, sizeof(struct linger));
+                       goto out_wakeup;
+               }
+       }
+@@ -877,7 +881,7 @@ static int event_srv_chk_r(int fd)
+       struct task *t = fdtab[fd].owner;
+       struct server *s = t->context;
+       char *desc;
+-      int done;
++      int done, shutr;
+       unsigned short msglen;
+       if (unlikely((s->result & SRV_CHK_ERROR) || (fdtab[fd].state == FD_STERROR))) {
+@@ -898,7 +902,7 @@ static int event_srv_chk_r(int fd)
+        * with running the checks without attempting another socket read.
+        */
+-      done = 0;
++      done = shutr = 0;
+       for (len = 0; s->check_data_len < global.tune.chksize; s->check_data_len += len) {
+               len = recv(fd, s->check_data + s->check_data_len, global.tune.chksize - s->check_data_len, 0);
+               if (len <= 0)
+@@ -906,14 +910,14 @@ static int event_srv_chk_r(int fd)
+       }
+       if (len == 0)
+-              done = 1; /* connection hangup received */
++              done = shutr = 1; /* connection hangup received */
+       else if (len < 0 && errno != EAGAIN) {
+               /* Report network errors only if we got no other data. Otherwise
+                * we'll let the upper layers decide whether the response is OK
+                * or not. It is very common that an RST sent by the server is
+                * reported as an error just after the last data chunk.
+                */
+-              done = 1;
++              done = shutr = 1;
+               if (!s->check_data_len) {
+                       if (!(s->result & SRV_CHK_ERROR))
+                               set_server_check_status(s, HCHK_STATUS_SOCKERR, NULL);
+@@ -1162,7 +1166,15 @@ static int event_srv_chk_r(int fd)
+       *s->check_data = '\0';
+       s->check_data_len = 0;
+-      /* Close the connection... */
++      /* Close the connection... We absolutely want to perform a hard close
++       * and reset the connection if some data are pending, otherwise we end
++       * up with many TIME_WAITs and eat all the source port range quickly.
++       * To avoid sending RSTs all the time, we first try to drain pending
++       * data.
++       */
++      if (!shutr && recv(fd, trash, trashlen, MSG_NOSIGNAL|MSG_DONTWAIT) > 0)
++              setsockopt(fd, SOL_SOCKET, SO_LINGER,
++                         (struct linger *) &nolinger, sizeof(struct linger));
+       shutdown(fd, SHUT_RDWR);
+       EV_FD_CLR(fd, DIR_RD);
+       task_wakeup(t, TASK_WOKEN_IO);
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0014-MEDIUM-checks-prevent-TIME_WAITs-from-appearin-1.4.22.diff b/net/haproxy/patches/0014-MEDIUM-checks-prevent-TIME_WAITs-from-appearin-1.4.22.diff
new file mode 100644 (file)
index 0000000..450133d
--- /dev/null
@@ -0,0 +1,29 @@
+From 4ee19c30abdd962fbc10f65c45a5f1615cda3059 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Fri, 23 Nov 2012 17:35:59 +0100
+Subject: MEDIUM: checks: prevent TIME_WAITs from appearing also on timeouts
+
+We need to disable lingering before closing on timeout too, otherwise
+we accumulate TIME_WAITs.
+(cherry picked from commit cfd97c6f043fb64980529a0ce26b10fecd0e8fe2)
+---
+ src/checks.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/src/checks.c b/src/checks.c
+index 3d01282..201900a 100644
+--- a/src/checks.c
++++ b/src/checks.c
+@@ -1527,6 +1527,9 @@ struct task *process_chk(struct task *t)
+                       else
+                               set_server_down(s);
+                       s->curfd = -1;
++                      /* avoid accumulating TIME_WAIT on timeouts */
++                      setsockopt(fd, SOL_SOCKET, SO_LINGER,
++                                 (struct linger *) &nolinger, sizeof(struct linger));
+                       fd_delete(fd);
+                       rv = 0;
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0015-BUG-MAJOR-cli-show-sess-id-may-randomly-corrup-1.4.22.diff b/net/haproxy/patches/0015-BUG-MAJOR-cli-show-sess-id-may-randomly-corrup-1.4.22.diff
new file mode 100644 (file)
index 0000000..f4817b1
--- /dev/null
@@ -0,0 +1,55 @@
+From 475b5ec3be8e022bd0f96331efc14c7b7b137d60 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Mon, 26 Nov 2012 02:22:40 +0100
+Subject: BUG/MAJOR: cli: show sess <id> may randomly corrupt the back-ref list
+
+show sess <id> puts a backref into the session it's dumping. If the output
+is interrupted, the backref cannot always be removed because it's only done
+in the I/O handler. This can randomly corrupt the backref list when the
+session closes, because it passes the pointer to the next session which
+itself might be watched.
+
+The case is hard to reproduce (hundreds of attempts) but monitoring systems
+might encounter it frequently.
+
+Thus we have to add a release handler which does the cleanup even when the
+I/O handler is not called.
+
+This issue should also be present in 1.4 so the patch should be backported.
+(cherry picked from commit 5f9a8779b3d4fb324dacc1daacfb478bd12963d1)
+
+NOTE: In 1.4 there is no release function so we have to hard-code the
+release in session.c when the condition is encountered.
+---
+ src/session.c |   15 +++++++++++++++
+ 1 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/src/session.c b/src/session.c
+index 0f6a1cf..239d4f5 100644
+--- a/src/session.c
++++ b/src/session.c
+@@ -989,6 +989,21 @@ resync_stream_interface:
+                       if (may_dequeue_tasks(s->srv, s->be))
+                               process_srv_queue(s->srv);
+               }
++
++              if (s->req->cons->iohandler == stats_io_handler &&
++                  s->req->cons->st0 == STAT_CLI_O_SESS && s->data_state == DATA_ST_LIST) {
++                      /* This is a fix for a design bug in the stats I/O handler :
++                       * "show sess $sess" may corrupt the struct session if not
++                       * properly detached. Unfortunately, in 1.4 there is no way
++                       * to ensure we always cleanly unregister an I/O handler upon
++                       * error. So we're doing the cleanup here if we can detect the
++                       * situation.
++                       */
++                      if (!LIST_ISEMPTY(&s->data_ctx.sess.bref.users)) {
++                              LIST_DEL(&s->data_ctx.sess.bref.users);
++                              LIST_INIT(&s->data_ctx.sess.bref.users);
++                      }
++              }
+       }
+       /*
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0016-BUG-MINOR-http-don-t-report-client-aborts-as-s-1.4.22.diff b/net/haproxy/patches/0016-BUG-MINOR-http-don-t-report-client-aborts-as-s-1.4.22.diff
new file mode 100644 (file)
index 0000000..b9af91a
--- /dev/null
@@ -0,0 +1,86 @@
+From 46169a35f95f2128bbf185c06eb535d9acb7ee61 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Mon, 26 Nov 2012 13:35:37 +0100
+Subject: BUG/MINOR: http: don't report client aborts as server errors
+
+If a client aborts with an abortonclose flag, the close is forwarded
+to the server and when server response is processed, the analyser thinks
+it's the server who has closed first, and logs flags "SD" or "SH" and
+counts a server error. In order to avoid this, we now first detect that
+the client has closed and log a client abort instead.
+
+This likely is the reason why many people have been observing a small rate
+of SD/SH flags without being able to find what the error was.
+
+This fix should probably be backported to 1.4.
+(cherry picked from commit f003d375ec5190e7d99cfa14a9b09e7ca6c55daf)
+---
+ src/proto_http.c |   37 +++++++++++++++++++++++++++++++++----
+ 1 files changed, 33 insertions(+), 4 deletions(-)
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index 1ad838b..ae37035 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -4919,6 +4919,28 @@ int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit)
+                       return 0;
+               }
++              /* client abort with an abortonclose */
++              else if ((rep->flags & BF_SHUTR) && ((s->req->flags & (BF_SHUTR|BF_SHUTW)) == (BF_SHUTR|BF_SHUTW))) {
++                      s->fe->counters.cli_aborts++;
++                      if (s->fe != s->be)
++                              s->be->counters.cli_aborts++;
++                      if (s->srv)
++                              s->srv->counters.cli_aborts++;
++              
++                      buffer_auto_close(rep);
++                      rep->analysers = 0;
++                      txn->status = 400;
++                      buffer_ignore(rep, rep->l - rep->send_max);
++                      stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_400));
++              
++                      if (!(s->flags & SN_ERR_MASK))
++                              s->flags |= SN_ERR_CLICL;
++                      if (!(s->flags & SN_FINST_MASK))
++                              s->flags |= SN_FINST_H;
++                      /* process_session() will take care of the error */
++                      return 0;
++              }
++
+               /* close from server, capture the response if the server has started to respond */
+               else if (rep->flags & BF_SHUTR) {
+                       if (msg->msg_state >= HTTP_MSG_RPVER || msg->err_pos >= 0)
+@@ -5666,8 +5688,18 @@ int http_response_forward_body(struct session *s, struct buffer *res, int an_bit
+       }
+  missing_data:
+-      /* stop waiting for data if the input is closed before the end */
++
++      if (res->flags & BF_SHUTW)
++              goto aborted_xfer;
++
++      /* stop waiting for data if the input is closed before the end. If the
++       * client side was already closed, it means that the client has aborted,
++       * so we don't want to count this as a server abort. Otherwise it's a
++       * server abort.
++       */
+       if (res->flags & BF_SHUTR) {
++              if ((res->flags & BF_SHUTW_NOW) || (s->req->flags & BF_SHUTR))
++                      goto aborted_xfer;
+               if (!(s->flags & SN_ERR_MASK))
+                       s->flags |= SN_ERR_SRVCL;
+               s->be->counters.srv_aborts++;
+@@ -5676,9 +5708,6 @@ int http_response_forward_body(struct session *s, struct buffer *res, int an_bit
+               goto return_bad_res_stats_ok;
+       }
+-      if (res->flags & BF_SHUTW)
+-              goto aborted_xfer;
+-
+       /* we need to obey the req analyser, so if it leaves, we must too */
+       if (!s->req->analysers)
+               goto return_bad_res;
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0017-BUG-MINOR-http-don-t-log-a-503-on-client-error-1.4.22.diff b/net/haproxy/patches/0017-BUG-MINOR-http-don-t-log-a-503-on-client-error-1.4.22.diff
new file mode 100644 (file)
index 0000000..c57f6e8
--- /dev/null
@@ -0,0 +1,31 @@
+From e856a82ac64d2fea6d2117627a9c857aca738bb0 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 4 Dec 2012 10:39:01 +0100
+Subject: BUG/MINOR: http: don't log a 503 on client errors while waiting for requests
+
+If a client aborts a request with an error (typically a TCP reset), we must
+log a 400. Till now we did not set the status nor close the stream interface,
+causing the request to attempt to be forwarded and logging a 503.
+
+Should be backported to 1.4 which is affected as well.
+(cherry picked from commit dc979f24929ad5352832730954c83ba47afe24cc)
+---
+ src/proto_http.c |    2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index ae37035..7a8872b 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -2506,6 +2506,8 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit)
+                       if (msg->err_pos >= 0)
+                               http_capture_bad_message(&s->fe->invalid_req, s, req, msg, msg->msg_state, s->fe);
++                      txn->status = 400;
++                      stream_int_retnclose(req->prod, NULL);
+                       msg->msg_state = HTTP_MSG_ERROR;
+                       req->analysers = 0;
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0018-BUG-MEDIUM-tcp-process-could-theorically-crash-1.4.22.diff b/net/haproxy/patches/0018-BUG-MEDIUM-tcp-process-could-theorically-crash-1.4.22.diff
new file mode 100644 (file)
index 0000000..aa0cdd7
--- /dev/null
@@ -0,0 +1,58 @@
+From 307227061df9938e9db5c0880254d71f2b9f5e83 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sat, 8 Dec 2012 23:03:28 +0100
+Subject: BUG/MEDIUM: tcp: process could theorically crash on lack of source ports
+
+When connect() fails with EAGAIN or EADDRINUSE, an error message is
+sent to logs and uses srv->id to indicate the server name (this is
+very old code). Since version 1.4, it is possible to have srv == NULL,
+so the message could cause a crash when connect() returns EAGAIN or
+EADDRINUSE. However in practice this does not happen because on lack
+of source ports, EADDRNOTAVAIL is returned instead, so this code is
+never called.
+
+This fix consists in not displaying the server name anymore, and in
+adding the test for EADDRNOTAVAIL.
+
+Also, the log level was lowered from LOG_EMERG to LOG_ERR in order
+not to spam all consoles when source ports are missing for a given
+target.
+
+This fix should be backported to 1.4.
+(cherry picked from commit b1719517b754aa0a098ee0f9c59e8babaf8df384)
+---
+ src/proto_tcp.c |   10 ++++------
+ 1 files changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/src/proto_tcp.c b/src/proto_tcp.c
+index 84fda20..e876d71 100644
+--- a/src/proto_tcp.c
++++ b/src/proto_tcp.c
+@@ -376,20 +376,18 @@ int tcpv4_connect_server(struct stream_interface *si,
+       if ((connect(fd, (struct sockaddr *)srv_addr, sizeof(struct sockaddr_in)) == -1) &&
+           (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
+-              if (errno == EAGAIN || errno == EADDRINUSE) {
++              if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) {
+                       char *msg;
+-                      if (errno == EAGAIN) /* no free ports left, try again later */
++                      if (errno == EAGAIN || errno == EADDRNOTAVAIL)
+                               msg = "no free ports";
+                       else
+                               msg = "local address already in use";
+-                      qfprintf(stderr,"Cannot connect: %s.\n",msg);
++                      qfprintf(stderr,"Connect() failed for backend %s: %s.\n", be->id, msg);
+                       port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port);
+                       fdinfo[fd].port_range = NULL;
+                       close(fd);
+-                      send_log(be, LOG_EMERG,
+-                               "Connect() failed for server %s/%s: %s.\n",
+-                               be->id, srv->id, msg);
++                      send_log(be, LOG_ERR, "Connect() failed for backend %s: %s.\n", be->id, msg);
+                       return SN_ERR_RESOURCE;
+               } else if (errno == ETIMEDOUT) {
+                       //qfprintf(stderr,"Connect(): ETIMEDOUT");
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0019-BUG-MINOR-http-don-t-abort-client-connection-o-1.4.22.diff b/net/haproxy/patches/0019-BUG-MINOR-http-don-t-abort-client-connection-o-1.4.22.diff
new file mode 100644 (file)
index 0000000..8f37489
--- /dev/null
@@ -0,0 +1,45 @@
+From dc624fd282caae163b11c197b36851e0ecf373eb Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Thu, 20 Dec 2012 12:10:09 +0100
+Subject: BUG/MINOR: http: don't abort client connection on premature responses
+
+When a server responds prematurely to a POST request, haproxy used to
+cause the transfer to be aborted before the end. This is problematic
+because this causes the client to receive a TCP reset when it tries to
+push more data, generally preventing it from receiving the response
+which contain the reason for the premature reponse (eg: "entity too
+large" or an authentication request).
+
+From now on we take care of allowing the upload traffic to flow to the
+server even when the response has been received, since the server is
+supposed to drain it. That way the client receives the server response.
+
+This bug has been present since 1.4 and the fix should probably be
+backported there.
+(cherry picked from commit 40f151aa79bcdf8b517c4e5666edbc7a47ea7fdc)
+
+Note: 1.4 does not have SI_FL_NOHALF but this is not important.
+---
+ src/proto_http.c |    5 +++--
+ 1 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index 7a8872b..e4cec6d 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -4443,9 +4443,10 @@ int http_resync_states(struct session *s)
+               buffer_auto_close(s->rep);
+               buffer_auto_read(s->rep);
+       }
+-      else if (txn->rsp.msg_state == HTTP_MSG_CLOSED ||
++      else if ((txn->req.msg_state >= HTTP_MSG_DONE &&
++                (txn->rsp.msg_state == HTTP_MSG_CLOSED || (s->rep->flags & BF_SHUTW))) ||
+                txn->rsp.msg_state == HTTP_MSG_ERROR ||
+-               (s->rep->flags & BF_SHUTW)) {
++               txn->req.msg_state == HTTP_MSG_ERROR) {
+               s->rep->analysers = 0;
+               buffer_auto_close(s->rep);
+               buffer_auto_read(s->rep);
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0020-BUILD-no-need-to-clean-up-when-making-git-tar-1.4.22.diff b/net/haproxy/patches/0020-BUILD-no-need-to-clean-up-when-making-git-tar-1.4.22.diff
new file mode 100644 (file)
index 0000000..ab2fe86
--- /dev/null
@@ -0,0 +1,28 @@
+From 24a528b3f5f09cdd9aebeb9531d7e76623329070 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Thu, 20 Dec 2012 15:00:44 +0100
+Subject: BUILD: no need to clean up when making git-tar
+
+git-tar uses the repository, not the working dir, so it's useless to
+run "make clean" first.
+(cherry picked from commit 05ed29cf6ef1eb6268c95c5d38af849c487eeedd)
+---
+ Makefile |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 9350d54..7633588 100644
+--- a/Makefile
++++ b/Makefile
+@@ -584,7 +584,7 @@ tar:       clean
+           -cf - haproxy-$(VERSION)/* | gzip -c9 >haproxy-$(VERSION).tar.gz
+       rm -f haproxy-$(VERSION)
+-git-tar: clean
++git-tar:
+       git archive --format=tar --prefix="haproxy-$(VERSION)/" HEAD | gzip -9 > haproxy-$(VERSION)$(SUBVERS).tar.gz
+ version:
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0021-MINOR-http-always-report-PR-flags-for-redirect-1.4.22.diff b/net/haproxy/patches/0021-MINOR-http-always-report-PR-flags-for-redirect-1.4.22.diff
new file mode 100644 (file)
index 0000000..3c41131
--- /dev/null
@@ -0,0 +1,30 @@
+From 528595f5989ef3af64c3e480ae15363677812aaa Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sun, 30 Dec 2012 00:27:36 +0100
+Subject: MINOR: http: always report PR-- flags for redirect rules
+
+Mainline commit 71241abf fixed a minor issue by which keep-alive requests
+causing a redirect did not have the PR-- flags while close requests did
+have it. This patch merges this part of the change which fixes the flags.
+---
+ src/proto_http.c |    4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/src/proto_http.c b/src/proto_http.c
+index e4cec6d..ffa2224 100644
+--- a/src/proto_http.c
++++ b/src/proto_http.c
+@@ -3476,6 +3476,10 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
+                               s->rep->analysers = AN_RES_HTTP_XFER_BODY;
+                               txn->req.msg_state = HTTP_MSG_CLOSED;
+                               txn->rsp.msg_state = HTTP_MSG_DONE;
++                              if (!(s->flags & SN_ERR_MASK))
++                                      s->flags |= SN_ERR_PRXCOND;
++                              if (!(s->flags & SN_FINST_MASK))
++                                      s->flags |= SN_FINST_R;
+                               break;
+                       } else {
+                               /* keep-alive not possible */
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0022-BUG-MINOR-time-frequency-counters-are-not-tota-1.4.22.diff b/net/haproxy/patches/0022-BUG-MINOR-time-frequency-counters-are-not-tota-1.4.22.diff
new file mode 100644 (file)
index 0000000..512426e
--- /dev/null
@@ -0,0 +1,124 @@
+From 44db294666f9dfb68667f998532781e898f14c4f Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sat, 29 Dec 2012 21:50:07 +0100
+Subject: BUG/MINOR: time: frequency counters are not totally accurate
+
+When a frontend is rate-limited to 1000 connections per second, the
+effective rate measured from the client is 999/s, and connections
+experience an average response time of 99.5 ms with a standard
+deviation of 2 ms.
+
+The reason for this inaccuracy is that when computing frequency
+counters, we use one part of the previous value proportional to the
+number of milliseconds remaining in the current second. But even the
+last millisecond still uses a part of the past value, which is wrong :
+since we have a 1ms resolution, the last millisecond must be dedicated
+only to filling the current second.
+
+So we slightly adjust the algorithm to use 999/1000 of the past value
+during the first millisecond, and 0/1000 of the past value during the
+last millisecond.  We also slightly improve the computation by computing
+the remaining time instead of the current time in tv_update_date(), so
+that we don't have to negate the value in each frequency counter.
+
+Now with the fix, the connection rate measured by both the client and
+haproxy is a steady 1000/s, the average response time measured is 99.2ms
+and more importantly, the standard deviation has been divided by 3 to
+0.6 millisecond.
+
+This fix should also be backported to 1.4 which has the same issue.
+(cherry picked from commit eab777c32eff7ee55a6ea12dd2f15fa14d66f233)
+---
+ include/common/time.h |    1 +
+ src/freq_ctr.c        |    7 +++----
+ src/time.c            |   16 +++++++++++++---
+ 3 files changed, 17 insertions(+), 7 deletions(-)
+
+diff --git a/include/common/time.h b/include/common/time.h
+index abc1ccf..c9e3641 100644
+--- a/include/common/time.h
++++ b/include/common/time.h
+@@ -55,6 +55,7 @@
+ #define SETNOW(a)             (*a=now)
+ extern unsigned int   curr_sec_ms;      /* millisecond of current second (0..999) */
++extern unsigned int   ms_left_scaled;   /* milliseconds left for current second (0..2^32-1) */
+ extern unsigned int   curr_sec_ms_scaled;  /* millisecond of current second (0..2^32-1) */
+ extern unsigned int   now_ms;           /* internal date in milliseconds (may wrap) */
+ extern struct timeval now;              /* internal date is a monotonic function of real clock */
+diff --git a/src/freq_ctr.c b/src/freq_ctr.c
+index 3df930f..8718b60 100644
+--- a/src/freq_ctr.c
++++ b/src/freq_ctr.c
+@@ -47,7 +47,7 @@ unsigned int read_freq_ctr(struct freq_ctr *ctr)
+       if (past <= 1 && !curr)
+               return past; /* very low rate, avoid flapping */
+-      return curr + mul32hi(past, ~curr_sec_ms_scaled);
++      return curr + mul32hi(past, ms_left_scaled);
+ }
+ /* returns the number of remaining events that can occur on this freq counter
+@@ -59,7 +59,6 @@ unsigned int freq_ctr_remain(struct freq_ctr *ctr, unsigned int freq, unsigned i
+       unsigned int curr, past;
+       unsigned int age;
+-      past = 0;
+       curr = 0;               
+       age = now.tv_sec - ctr->curr_sec;
+@@ -69,7 +68,7 @@ unsigned int freq_ctr_remain(struct freq_ctr *ctr, unsigned int freq, unsigned i
+                       curr = past;
+                       past = ctr->prev_ctr;
+               }
+-              curr += mul32hi(past, ~curr_sec_ms_scaled);
++              curr += mul32hi(past, ms_left_scaled);
+       }
+       curr += pend;
+@@ -99,7 +98,7 @@ unsigned int next_event_delay(struct freq_ctr *ctr, unsigned int freq, unsigned
+                       curr = past;
+                       past = ctr->prev_ctr;
+               }
+-              curr += mul32hi(past, ~curr_sec_ms_scaled);
++              curr += mul32hi(past, ms_left_scaled);
+       }
+       curr += pend;
+diff --git a/src/time.c b/src/time.c
+index 1b0f72c..342be9d 100644
+--- a/src/time.c
++++ b/src/time.c
+@@ -16,8 +16,8 @@
+ #include <common/standard.h>
+ #include <common/time.h>
+-unsigned int   curr_sec_ms;      /* millisecond of current second (0..999) */
+-unsigned int   curr_sec_ms_scaled;  /* millisecond of current second (0..2^32-1) */
++unsigned int   curr_sec_ms;     /* millisecond of current second (0..999) */
++unsigned int   ms_left_scaled;  /* milliseconds left for current second (0..2^32-1) */
+ unsigned int   now_ms;          /* internal date in milliseconds (may wrap) */
+ struct timeval now;             /* internal date is a monotonic function of real clock */
+ struct timeval date;            /* the real current date */
+@@ -195,7 +195,17 @@ REGPRM2 void tv_update_date(int max_wait, int interrupted)
+  to_ms:
+       now = adjusted;
+       curr_sec_ms = now.tv_usec / 1000;            /* ms of current second */
+-      curr_sec_ms_scaled = curr_sec_ms * 4294971;  /* ms * 2^32 / 1000 */
++
++      /* For frequency counters, we'll need to know the ratio of the previous
++       * value to add to current value depending on the current millisecond.
++       * The principle is that during the first millisecond, we use 999/1000
++       * of the past value and that during the last millisecond we use 0/1000
++       * of the past value. In summary, we only use the past value during the
++       * first 999 ms of a second, and the last ms is used to complete the
++       * current measure. The value is scaled to (2^32-1) so that a simple
++       * multiply followed by a shift gives us the final value.
++       */
++      ms_left_scaled = (999U - curr_sec_ms) * 4294967U;
+       now_ms = now.tv_sec * 1000 + curr_sec_ms;
+       return;
+ }
+-- 
+1.7.1
+
diff --git a/net/haproxy/patches/0023-BUG-MINOR-http-don-t-process-abortonclose-when-1.4.22.diff b/net/haproxy/patches/0023-BUG-MINOR-http-don-t-process-abortonclose-when-1.4.22.diff
new file mode 100644 (file)
index 0000000..8e591f4
--- /dev/null
@@ -0,0 +1,35 @@
+From d978423607b6666ca8dd3257d860558ead1b94af Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sun, 30 Dec 2012 00:50:35 +0100
+Subject: BUG/MINOR: http: don't process abortonclose when request was sent
+
+option abortonclose may cause a valid connection to be aborted just
+after the request has been sent. This is because we check for it
+during the session establishment sequence before checking for write
+activity. So if the abort and the connect complete at the same time,
+the abort is still considered. Let's check for an explicity partial
+write before aborting.
+
+This fix should be backported to 1.4 too.
+(cherry picked from commit a7a7ebc38280d7a04192bf95e6852222f4bd8140)
+---
+ src/session.c |    3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/src/session.c b/src/session.c
+index 239d4f5..6211a45 100644
+--- a/src/session.c
++++ b/src/session.c
+@@ -203,7 +203,8 @@ int sess_update_st_con_tcp(struct session *s, struct stream_interface *si)
+       }
+       /* OK, maybe we want to abort */
+-      if (unlikely((rep->flags & BF_SHUTW) ||
++      if (!(req->flags & BF_WRITE_PARTIAL) &&
++          unlikely((rep->flags & BF_SHUTW) ||
+                    ((req->flags & BF_SHUTW_NOW) && /* FIXME: this should not prevent a connection from establishing */
+                     (((req->flags & (BF_OUT_EMPTY|BF_WRITE_ACTIVITY)) == BF_OUT_EMPTY) ||
+                      s->be->options & PR_O_ABRT_CLOSE)))) {
+-- 
+1.7.1
+