* released 1.1.12
* fixed stats monitoring, and optimized some tv_* for most common cases.
* replaced temporary 'newhdr' with 'trash' to reduce stack size
* made HTTP errors more HTML-fiendly.
* renamed strlcpy() to strlcpy2() because of a slightly difference between
  their behaviour (return value), to avoid confusion.
* restricted HTTP messages to HTTP proxies only
* added a 502 message when the connection has been refused by the server,
  to prevent clients from believing this is a zero-byte HTTP 0.9 reply.
* changed 'Cache-control:' from 'no-cache="set-cookie"' to 'private' when
  inserting a cookie, because some caches (apache) don't understand it.
* fixed processing of server headers when client is in SHUTR state
* automatically close fd's 0,1 and 2 when going daemon ; setpgrp() after
  setpgid()
* updated the Makefile and the Formilux build script
diff --git a/Makefile b/Makefile
index 88ed19c..70d5008 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,12 @@
+# Select target OS. TARGET must match a system for which COPTS and LIBS are
+# correctly defined below.
+# You can set it on make's command line. eg: make TARGET=solaris
+TARGET = linux24
+#TARGET = linux22
+#TARGET = solaris
+#TARGET = solarisv9
+#TARGET = openbsd
+
 CC = gcc
 LD = gcc
 
@@ -10,20 +19,17 @@
 LIBS.linux22 =
 
 # This is for Solaris 8
-COPTS.solaris = -O2 -fomit-frame-pointer -DSOLARIS -DHAVE_STRLCPY
+COPTS.solaris = -O2 -fomit-frame-pointer -DSOLARIS
 LIBS.solaris = -lnsl -lsocket
 
+# This is for Solaris 8 on UltraSparc2 processor
+COPTS.solarisv9 = -O6 -mcpu=v9 -fomit-frame-pointer -DSOLARIS
+LIBS.solarisv9 = -lnsl -lsocket
+
 # This is for OpenBSD 3.0
-COPTS.openbsd = -O2 -DHAVE_STRLCPY
+COPTS.openbsd = -O2
 LIBS.openbsd =
 
-# Select target OS. TARGET must match a system for which COPTS and LIBS are
-# correctly defined above.
-TARGET = linux24
-#TARGET = linux22
-#TARGET = solaris
-#TARGET = openbsd
-
 #DEBUG =
 DEBUG = -g
 
diff --git a/examples/haproxy-1.1.12-flx.1.pkg b/examples/haproxy-1.1.12-flx.1.pkg
new file mode 100644
index 0000000..49ea3f6
--- /dev/null
+++ b/examples/haproxy-1.1.12-flx.1.pkg
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+function do_compile {
+    $FLXMAKE COPTS="-march=$arch -mcpu=$cpu -O2 -mpreferred-stack-boundary=2 -malign-loops=0 -malign-jumps=0 -DNETFILTER -DTRANSPARENT"
+}
+
+function do_prepack {
+    mkdir -p $ROOTDIR/sbin/init.d ; cp init.d/haproxy $ROOTDIR/sbin/init.d
+    mkdir -p $ROOTDIR/usr/sbin ; cp haproxy $ROOTDIR/usr/sbin
+    mkdir -p $ROOTDIR/usr/share/examples/$PKGRADIX-$PKGVER/etc
+    cp examples/haproxy.cfg $ROOTDIR/usr/share/examples/$PKGRADIX-$PKGVER/etc/haproxy.cfg
+    cp examples/rc.highsock $ROOTDIR/usr/share/examples/$PKGRADIX-$PKGVER/etc/rc.highsock
+    cp examples/config.rc.haproxy $ROOTDIR/usr/share/examples/$PKGRADIX-$PKGVER/etc/config.rc.haproxy
+    mkdir -p $ROOTDIR/usr/share/$PKGRADIX-$PKGVER ; cp doc/haproxy.txt $ROOTDIR/usr/share/$PKGRADIX-$PKGVER
+    ln -s ../examples/$PKGRADIX-$PKGVER $ROOTDIR/usr/share/$PKGRADIX-$PKGVER/examples
+    make clean
+}
+
diff --git a/examples/haproxy-1.1.5-flx.1-i686.pkg b/examples/haproxy-1.1.5-flx.1-i686.pkg
deleted file mode 100644
index 3fad897..0000000
--- a/examples/haproxy-1.1.5-flx.1-i686.pkg
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-
-function do_compile {
-    make COPTS="-march=i586 -mcpu=i686 -O2 -mpreferred-stack-boundary=2 -malign-loops=0 -malign-jumps=0 -DNETFILTER -DTRANSPARENT"
-}
-
-function do_prepack {
-    mkdir -p $ROOTDIR/sbin/init.d ; cp init.d/haproxy $ROOTDIR/sbin/init.d
-    mkdir -p $ROOTDIR/usr/sbin ; cp haproxy $ROOTDIR/usr/sbin
-    mkdir -p $ROOTDIR/usr/share/sample/etc/haproxy ; cp examples/cfg $ROOTDIR/usr/share/sample/etc/haproxy/haproxy.cfg
-    cp examples/rc.highsock $ROOTDIR/usr/share/sample/etc/haproxy/rc.highsock
-    cp examples/config.rc.haproxy $ROOTDIR/usr/share/sample/etc/config.rc.haproxy
-    mkdir -p $ROOTDIR/usr/share/haproxy ; cp doc/haproxy.txt $ROOTDIR/usr/share/haproxy
-    make clean
-}
-
diff --git a/examples/haproxy.cfg b/examples/haproxy.cfg
index 44fd8d7..4e8b434 100644
--- a/examples/haproxy.cfg
+++ b/examples/haproxy.cfg
@@ -42,11 +42,11 @@
 	clitimeout	50000
 	srvtimeout	50000
 
-	reqidel ^Connection:		# desactivation du keep-alive
+	reqidel ^Connection:		# disable keep-alive
 	reqadd  Connection:\ close
 	rspidel ^Connection:
 	rspadd  Connection:\ close
-	rspidel ^Set-cookie:\ IP=	# ne pas laisser sortir une adresse privee
+	rspidel ^Set-cookie:\ IP=	# do not let this cookie tell our internal IP address
 	
 listen	appli3-relais 0.0.0.0:10003
 	log	global
diff --git a/haproxy.c b/haproxy.c
index e6721d7..9e3f7e0 100644
--- a/haproxy.c
+++ b/haproxy.c
@@ -7,7 +7,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * Pending bugs :
+ * Pending bugs (may be not fixed because not reproduced) :
  *   - solaris only : sometimes, an HTTP proxy with only a dispatch address causes
  *     the proxy to terminate (no core) if the client breaks the connection during
  *     the response. Seen on 1.1.8pre4, but never reproduced. May not be related to
@@ -17,6 +17,21 @@
  *
  * ChangeLog :
  *
+ * 2002/07/13 : 1.1.12
+ *   - fixed stats monitoring, and optimized some tv_* for most common cases.
+ *   - replaced temporary 'newhdr' with 'trash' to reduce stack size
+ *   - made HTTP errors more HTML-fiendly.
+ *   - renamed strlcpy() to strlcpy2() because of a slightly difference between
+ *     their behaviour (return value), to avoid confusion.
+ *   - restricted HTTP messages to HTTP proxies only
+ *   - added a 502 message when the connection has been refused by the server,
+ *     to prevent clients from believing this is a zero-byte HTTP 0.9 reply.
+ *   - changed 'Cache-control:' from 'no-cache="set-cookie"' to 'private' when
+ *     inserting a cookie, because some caches (apache) don't understand it.
+ *   - fixed processing of server headers when client is in SHUTR state
+ * 2002/07/04 :
+ *   - automatically close fd's 0,1 and 2 when going daemon ; setpgrp() after
+ *     setpgid()
  * 2002/06/04 : 1.1.11
  *   - fixed multi-cookie handling in client request to allow clean deletion
  *     in insert+indirect mode. Now, only the server cookie is deleted and not
@@ -153,8 +168,8 @@
 #include <linux/netfilter_ipv4.h>
 #endif
 
-#define HAPROXY_VERSION "1.1.11"
-#define HAPROXY_DATE	"2002/06/04"
+#define HAPROXY_VERSION "1.1.12"
+#define HAPROXY_DATE	"2002/07/13"
 
 /* this is for libc5 for example */
 #ifndef TCP_NODELAY
@@ -222,8 +237,6 @@
 /* if a < min, then bound <a> to <min>. The macro returns the new <a> */
 #define LBOUND(a, min)	({ typeof(a) b = (min); if ((a) < b) (a) = b; (a); })
 
-
-#ifndef HAVE_STRLCPY
 /*
  * copies at most <size-1> chars from <src> to <dst>. Last char is always
  * set to 0, unless <size> is 0. The number of chars copied is returned
@@ -231,7 +244,7 @@
  * This code has been optimized for size and speed : on x86, it's 45 bytes
  * long, uses only registers, and consumes only 4 cycles per char.
  */
-int strlcpy(char *dst, const char *src, int size) {
+int strlcpy2(char *dst, const char *src, int size) {
     char *orig = dst;
     if (size) {
 	while (--size && (*dst = *src)) {
@@ -241,8 +254,6 @@
     }
     return dst - orig;
 }
-#endif
-
 
 #define MEM_OPTIM
 #ifdef	MEM_OPTIM
@@ -558,6 +569,7 @@
 static struct timeval now = {0,0};	/* the current date at any moment */
 
 static regmatch_t pmatch[MAX_MATCH];  /* rm_so, rm_eo for regular expressions */
+/* this is used to drain data, and as a temporary buffer for sprintf()... */
 static char trash[BUFSIZE];
 
 /*
@@ -594,32 +606,49 @@
 	"Cache-Control: no-cache\r\n"
 	"Connection: close\r\n"
 	"\r\n"
-	"400 Bad request : Your browser sent an invalid request.\r\n";
+	"<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n";
 
 const char *HTTP_403 =
 	"HTTP/1.0 403 Forbidden\r\n"
 	"Cache-Control: no-cache\r\n"
 	"Connection: close\r\n"
 	"\r\n"
+	"<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n";
+
+const char *HTTP_500 =
+	"HTTP/1.0 500 Server Error\r\n"
+	"Cache-Control: no-cache\r\n"
+	"Connection: close\r\n"
+	"\r\n"
-	"403 Forbidden : Request forbidden by administrative rules.\r\n";
+	"<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n";
 
 const char *HTTP_502 =
 	"HTTP/1.0 502 Proxy Error\r\n"
 	"Cache-Control: no-cache\r\n"
 	"Connection: close\r\n"
 	"\r\n"
-	"502 Proxy Error : No server is available to handle this request.\r\n";
+	"<html><body><h1>502 Proxy Error</h1>\nNo server is available to handle this request.\n</body></html>\n";
 
 /*********************************************************************/
 /*  statistics  ******************************************************/
 /*********************************************************************/
 
+#if STATTIME > 0
 static int stats_tsk_lsrch, stats_tsk_rsrch,
     stats_tsk_good, stats_tsk_right, stats_tsk_left,
     stats_tsk_new, stats_tsk_nsrch;
+#endif
 
 
 /*********************************************************************/
+/*  debugging  *******************************************************/
+/*********************************************************************/
+#ifdef DEBUG_FULL
+static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
+static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
+#endif
+
+/*********************************************************************/
 /*  function prototypes  *********************************************/
 /*********************************************************************/
 
@@ -905,14 +934,14 @@
  * compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
  */
 static inline int tv_cmp(struct timeval *tv1, struct timeval *tv2) {
-    if (tv1->tv_sec > tv2->tv_sec)
-	return 1;
-    else if (tv1->tv_sec < tv2->tv_sec)
+    if (tv1->tv_sec < tv2->tv_sec)
 	return -1;
-    else if (tv1->tv_usec > tv2->tv_usec)
+    else if (tv1->tv_sec > tv2->tv_sec)
 	return 1;
     else if (tv1->tv_usec < tv2->tv_usec)
 	return -1;
+    else if (tv1->tv_usec > tv2->tv_usec)
+	return 1;
     else
 	return 0;
 }
@@ -928,7 +957,7 @@
     cmp = tv_cmp(tv1, tv2);
     if (!cmp)
 	return 0; /* same dates, null diff */
-    else if (cmp<0) {
+    else if (cmp < 0) {
 	struct timeval *tmp = tv1;
 	tv1 = tv2;
 	tv2 = tmp;
@@ -942,23 +971,37 @@
 }
 
 /*
+ * returns the difference, in ms, between tv1 and tv2
+ */
+static inline unsigned long tv_diff(struct timeval *tv1, struct timeval *tv2) {
+    unsigned long ret;
+  
+    ret = (tv1->tv_sec - tv2->tv_sec) * 1000;
+    if (tv1->tv_usec > tv2->tv_usec)
+	ret += (tv1->tv_usec - tv2->tv_usec) / 1000;
+    else
+	ret -= (tv2->tv_usec - tv1->tv_usec) / 1000;
+    return (unsigned long) ret;
+}
+
+/*
  * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
  */
 static inline int tv_cmp_ms(struct timeval *tv1, struct timeval *tv2) {
     if (tv1->tv_sec == tv2->tv_sec) {
-	if (tv1->tv_usec > tv2->tv_usec + 1000)
-	    return 1;
-	else if (tv2->tv_usec > tv1->tv_usec + 1000)
+	if (tv2->tv_usec > tv1->tv_usec + 1000)
 	    return -1;
+	else if (tv1->tv_usec > tv2->tv_usec + 1000)
+	    return 1;
 	else
 	    return 0;
     }
-    else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
-	((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
-	return 1;
     else if ((tv2->tv_sec > tv1->tv_sec + 1) ||
 	     ((tv2->tv_sec == tv1->tv_sec + 1) && (tv2->tv_usec + 1000000 > tv1->tv_usec + 1000)))
 	return -1;
+    else if ((tv1->tv_sec > tv2->tv_sec + 1) ||
+	     ((tv1->tv_sec == tv2->tv_sec + 1) && (tv1->tv_usec + 1000000 > tv2->tv_usec + 1000)))
+	return 1;
     else
 	return 0;
 }
@@ -1155,12 +1198,15 @@
     if (task->prev == NULL) {
 	//	start_from = list;
 	start_from = list->prev;
+#if STATTIME > 0
 	stats_tsk_new++;
-
+#endif
 	/* insert the unlinked <task> into the list, searching back from the last entry */
 	while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
 	    start_from = start_from->prev;
+#if STATTIME > 0
 	    stats_tsk_nsrch++;
+#endif
 	}
 	
 	//	  while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
@@ -1172,32 +1218,61 @@
 	     tv_cmp2(&task->expire, &task->prev->expire) >= 0) { /* walk right */
 	start_from = task->next;
 	if (start_from == list || tv_cmp2(&task->expire, &start_from->expire) <= 0) {
+#if STATTIME > 0
 	    stats_tsk_good++;
+#endif
 	    return task; /* it's already in the right place */
 	}
 
+#if STATTIME > 0
 	stats_tsk_right++;
+#endif
+
+	/* if the task is not at the right place, there's little chance that
+	 * it has only shifted a bit, and it will nearly always be queued
+	 * at the end of the list because of constant timeouts
+	 * (observed in real case).
+	 */
+#ifndef WE_REALLY_THINK_THAT_THIS_TASK_MAY_HAVE_SHIFTED
+	start_from = list->prev; /* assume we'll queue to the end of the list */
+	while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
+	    start_from = start_from->prev;
+#if STATTIME > 0
+	    stats_tsk_lsrch++;
+#endif
+	}
+#else /* WE_REALLY_... */
 	/* insert the unlinked <task> into the list, searching after position <start_from> */
 	while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
 	    start_from = start_from->next;
+#if STATTIME > 0
 	    stats_tsk_rsrch++;
+#endif
 	}
+#endif /* WE_REALLY_... */
+
 	/* we need to unlink it now */
 	task_delete(task);
     }
     else { /* walk left. */
+#if STATTIME > 0
 	stats_tsk_left++;
+#endif
 #ifdef LEFT_TO_TOP	/* not very good */
 	start_from = list;
 	while (start_from->next != list && tv_cmp2(&task->expire, &start_from->next->expire) > 0) {
 	    start_from = start_from->next;
+#if STATTIME > 0
 	    stats_tsk_lsrch++;
+#endif
 	}
 #else
 	start_from = task->prev->prev; /* valid because of the previous test above */
 	while (start_from != list && tv_cmp2(&task->expire, &start_from->expire) < 0) {
 	    start_from = start_from->prev;
+#if STATTIME > 0
 	    stats_tsk_lsrch++;
+#endif
 	}
 #endif
 	/* we need to unlink it now */
@@ -2110,6 +2185,9 @@
     struct buffer *req = t->req;
     struct buffer *rep = t->rep;
 
+#ifdef DEBUG_FULL
+    fprintf(stderr,"process_cli: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
+#endif
     //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
     //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
     //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
@@ -2127,7 +2205,6 @@
 		ptr++;
 	    
 	    if (ptr == req->h) { /* empty line, end of headers */
-		char newhdr[MAXREWRITE + 1];
 		int line, len;
 		/* we can only get here after an end of headers */
 		/* we'll have something else to do here : add new headers ... */
@@ -2135,28 +2212,29 @@
 		if (t->flags & SN_CLDENY) {
 		    /* no need to go further */
 		    t->logs.status = 403;
-		    client_retnclose(t, strlen(HTTP_403), HTTP_403);
+		    if (t->proxy->mode == PR_MODE_HTTP)
+			client_retnclose(t, strlen(HTTP_403), HTTP_403);
 		    return 1;
 		}
 
 		for (line = 0; line < t->proxy->nb_reqadd; line++) {
-		    len = sprintf(newhdr, "%s\r\n", t->proxy->req_add[line]);
-		    buffer_replace2(req, req->h, req->h, newhdr, len);
+		    len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
+		    buffer_replace2(req, req->h, req->h, trash, len);
 		}
 
 		if (t->proxy->options & PR_O_FWDFOR) {
 		    /* insert an X-Forwarded-For header */
 		    unsigned char *pn;
 		    pn = (unsigned char *)&t->cli_addr.sin_addr;
-		    len = sprintf(newhdr, "X-Forwarded-For: %d.%d.%d.%d\r\n",
+		    len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
 				  pn[0], pn[1], pn[2], pn[3]);
-		    buffer_replace2(req, req->h, req->h, newhdr, len);
+		    buffer_replace2(req, req->h, req->h, trash, len);
 		}
 
 		t->cli_state = CL_STDATA;
 		req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
 
-		t->logs.t_request = tv_delta(&t->logs.tv_accept, &now);
+		t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
 		/* FIXME: we'll set the client in a wait state while we try to
 		 * connect to the server. Is this really needed ? wouldn't it be
 		 * better to release the maximum of system buffers instead ? */
@@ -2196,8 +2274,9 @@
 
 		if ((t->logs.uri = pool_alloc(requri)) == NULL) {
 		    Alert("HTTP logging : out of memory.\n");
-		    t->logs.status = 502;
-		    client_retnclose(t, strlen(HTTP_502), HTTP_502);
+		    t->logs.status = 500;
+		    if (t->proxy->mode == PR_MODE_HTTP)
+			client_retnclose(t, strlen(HTTP_500), HTTP_500);
 		    return 1;
 		}
 		
@@ -2218,7 +2297,7 @@
 		len = sprintf(trash, "clihdr[%04x:%04x]: ", (unsigned  short)t->cli_fd, (unsigned short)t->srv_fd);
 		max = ptr - req->h;
 		UBOUND(max, sizeof(trash) - len - 1);
-		len += strlcpy(trash + len, req->h, max + 1);
+		len += strlcpy2(trash + len, req->h, max + 1);
 		trash[len++] = '\n';
 		write(1, trash, len);
 	    }
@@ -2415,7 +2494,8 @@
 	 */
 	if (req->l >= req->rlim - req->data) {
 	    t->logs.status = 400;
-	    client_retnclose(t, strlen(HTTP_400), HTTP_400);
+	    if (t->proxy->mode == PR_MODE_HTTP)
+		client_retnclose(t, strlen(HTTP_400), HTTP_400);
 	    return 1;
 	}
 	else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL
@@ -2577,7 +2657,9 @@
     struct buffer *req = t->req;
     struct buffer *rep = t->rep;
 
-    //fprintf(stderr,"process_srv: c=%d, s=%d\n", c, s);
+#ifdef DEBUG_FULL
+    fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
+#endif
     //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
     //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
     //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
@@ -2614,7 +2696,8 @@
 		    tv_eternity(&t->cnexpire);
 		    t->srv_state = SV_STCLOSE;
 		    t->logs.status = 502;
-		    client_return(t, strlen(HTTP_502), HTTP_502);
+		    if (t->proxy->mode == PR_MODE_HTTP)
+			client_return(t, strlen(HTTP_502), HTTP_502);
 		}
 	    }
 	    return 1;
@@ -2643,10 +2726,13 @@
 	    /* if conn_retries < 0 or other error, let's abort */
 	    tv_eternity(&t->cnexpire);
 	    t->srv_state = SV_STCLOSE;
+	    t->logs.status = 502;
+	    if (t->proxy->mode == PR_MODE_HTTP)
+		client_return(t, strlen(HTTP_502), HTTP_502);
 	    return 1;
 	}
 	else { /* no error or write 0 */
-	    t->logs.t_connect = tv_delta(&t->logs.tv_accept, &now);
+	    t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
 
 	    //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
 	    if (req->l == 0) /* nothing to write */
@@ -2686,7 +2772,6 @@
 		ptr++;
 	    
 	    if (ptr == rep->h) {
-		char newhdr[MAXREWRITE + 1];
 		int line, len;
 
 		/* we can only get here after an end of headers */
@@ -2696,23 +2781,30 @@
 		    /* the server is known, it's not the one the client requested, we have to
 		     * insert a set-cookie here.
 		     */
-		    len = sprintf(newhdr, "Set-Cookie: %s=%s; path=/\r\n",
+		    len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
 				  t->proxy->cookie_name, t->srv->cookie);
+
+		    /* Here, we will tell an eventual cache on the client side that we don't
+		     * want it to cache this reply because HTTP/1.0 caches also cache cookies !
+		     * Some caches understand the correct form: 'no-cache="set-cookie"', but
+		     * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
+		     */
 		    if (t->proxy->options & PR_O_COOK_NOC)
-			len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
+			//len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
+			len += sprintf(trash + len, "Cache-control: private\r\n");
 
-		    buffer_replace2(rep, rep->h, rep->h, newhdr, len);
+		    buffer_replace2(rep, rep->h, rep->h, trash, len);
 		}
 
 		/* headers to be added */
 		for (line = 0; line < t->proxy->nb_rspadd; line++) {
-		    len = sprintf(newhdr, "%s\r\n", t->proxy->rsp_add[line]);
-		    buffer_replace2(rep, rep->h, rep->h, newhdr, len);
+		    len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
+		    buffer_replace2(rep, rep->h, rep->h, trash, len);
 		}
 
 		t->srv_state = SV_STDATA;
 		rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
-		t->logs.t_data = tv_delta(&t->logs.tv_accept, &now);
+		t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
 		break;
 	    }
 
@@ -2756,7 +2848,7 @@
 		len = sprintf(trash, "srvhdr[%04x:%04x]: ", (unsigned  short)t->cli_fd, (unsigned short)t->srv_fd);
 		max = ptr - rep->h;
 		UBOUND(max, sizeof(trash) - len - 1);
-		len += strlcpy(trash + len, rep->h, max + 1);
+		len += strlcpy2(trash + len, rep->h, max + 1);
 		trash[len++] = '\n';
 		write(1, trash, len);
 	    }
@@ -2909,7 +3001,11 @@
 	    
 	}	
 	/* write timeout, or last client read and buffer empty */
-	else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
+	/* FIXME!!! here, we don't want to switch to SHUTW if the
+	 * client shuts read too early, because we may still have
+	 * some work to do on the headers.
+	 */
+	else if (((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) ||
 		 (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
 	    FD_CLR(t->srv_fd, StaticWriteEvent);
 	    tv_eternity(&t->swexpire);
@@ -3114,7 +3210,7 @@
 	write(1, trash, len);
     }
 
-    s->logs.t_close = tv_delta(&s->logs.tv_accept, &now);
+    s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
     if (s->rep != NULL)
 	s->logs.bytes = s->rep->total;
 
@@ -3422,9 +3518,9 @@
     unsigned long totaltime, deltatime;
     int ret;
 
-    if (tv_remain(&now, &nextevt) == 0) {
-	deltatime = (tv_delta(&now, &lastevt)?:1);
-	totaltime = (tv_delta(&now, &starttime)?:1);
+    if (tv_cmp(&now, &nextevt) > 0) {
+	deltatime = (tv_diff(&now, &lastevt)?:1);
+	totaltime = (tv_diff(&now, &starttime)?:1);
 	
 	if (global.mode & MODE_STATS) {	
 		if ((lines++ % 16 == 0) && !(global.mode & MODE_LOG))
@@ -4557,7 +4653,7 @@
 	/* command line debug mode inhibits configuration mode */
 	global.mode &= ~(MODE_DAEMON | MODE_QUIET);
     }
-    global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG));
+    global.mode |= (arg_mode & (MODE_DAEMON | MODE_QUIET | MODE_DEBUG | MODE_STATS | MODE_LOG));
 
     if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
 	Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
@@ -4727,8 +4823,20 @@
 	if (proc == global.nbproc)
 	    exit(0); /* parent must leave */
 
+	/* if we're NOT in QUIET mode, we should now close the 3 first FDs to ensure
+	 * that we can detach from the TTY. We MUST NOT do it in other cases since
+	 * it would have already be done, and 0-2 would have been affected to listening
+	 * sockets
+	 */
+    	if (!(global.mode & MODE_QUIET)) {
+	    /* detach from the tty */
+	    fclose(stdin); fclose(stdout); fclose(stderr);
+	    close(0); close(1); close(2); /* close all fd's */
+    	    global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
+	}
 	pid = getpid(); /* update child's pid */
 	setpgid(1, 0);
+	setpgrp();
     }
 
     select_loop();