[MEDIUM] implement the statistics output on a unix socket

A unix socket can now access the statistics. It currently only
recognizes the "show stat\n" command at the beginning of the
input, then returns the statistics in CSV format.
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 13196e2..3fdac86 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -47,6 +47,88 @@
 
 /*
  * Produces statistics data for the session <s>. Expects to be called with
+ * s->cli_state == CL_STSHUTR. It *may* make use of informations from <uri>
+ * and <flags>.
+ * It returns 0 if it had to stop writing data and an I/O is needed, 1 if the
+ * dump is finished and the session must be closed, or -1 in case of any error.
+ */
+int stats_dump_raw(struct session *s, struct uri_auth *uri, int flags)
+{
+	struct buffer *rep = s->rep;
+	struct proxy *px;
+	struct chunk msg;
+
+	msg.len = 0;
+	msg.str = trash;
+
+	switch (s->data_state) {
+	case DATA_ST_INIT:
+		/* the function had not been called yet, let's prepare the
+		 * buffer for a response.
+		 */
+		client_retnclose(s, &msg);
+		s->data_state = DATA_ST_HEAD;
+		/* fall through */
+
+	case DATA_ST_HEAD:
+		chunk_printf(&msg, sizeof(trash),
+			     "# pxname,svname,"
+			     "qcur,qmax,"
+			     "scur,smax,slim,stot,"
+			     "bin,bout,"
+			     "dreq,dresp,"
+			     "ereq,econ,eresp,"
+			     "weight,act,bck,"
+			     "chkfail,chkdown"
+			     "\n");
+			
+		if (buffer_write_chunk(rep, &msg) != 0)
+			return 0;
+
+		s->data_state = DATA_ST_INFO;
+		/* fall through */
+
+	case DATA_ST_INFO:
+		memset(&s->data_ctx, 0, sizeof(s->data_ctx));
+
+		s->data_ctx.stats.px = proxy;
+		s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
+		s->data_state = DATA_ST_LIST;
+		/* fall through */
+
+	case DATA_ST_LIST:
+		/* dump proxies */
+		while (s->data_ctx.stats.px) {
+			px = s->data_ctx.stats.px;
+			/* skip the disabled proxies and non-networked ones */
+			if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
+				if (stats_dump_proxy(s, px, NULL, 0) == 0)
+					return 0;
+
+			s->data_ctx.stats.px = px->next;
+			s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
+		}
+		/* here, we just have reached the last proxy */
+
+		s->data_state = DATA_ST_END;
+		/* fall through */
+
+	case DATA_ST_END:
+		s->data_state = DATA_ST_FIN;
+		return 1;
+
+	case DATA_ST_FIN:
+		return 1;
+
+	default:
+		/* unknown state ! */
+		return -1;
+	}
+}
+
+
+/*
+ * Produces statistics data for the session <s>. Expects to be called with
  * s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
  * flag from the session, which it uses to keep on being called when there is
  * free space in the buffer, of simply by letting an empty buffer upon return.
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index e23d1d4..d8c0a90 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -45,11 +45,13 @@
 #include <proto/acl.h>
 #include <proto/backend.h>
 #include <proto/buffers.h>
+#include <proto/dumpstats.h>
 #include <proto/fd.h>
 #include <proto/log.h>
 #include <proto/protocols.h>
 #include <proto/proto_uxst.h>
 #include <proto/queue.h>
+#include <proto/senddata.h>
 #include <proto/session.h>
 #include <proto/stream_sock.h>
 #include <proto/task.h>
@@ -401,6 +403,7 @@
 		memset(&s->logs, 0, sizeof(s->logs));
 		memset(&s->txn, 0, sizeof(s->txn));
 
+		s->data_state = DATA_ST_INIT;
 		s->data_source = DATA_SRC_NONE;
 		s->uniq_id = totalconn;
 
@@ -460,7 +463,6 @@
 		if (l->timeout && tv_isset(l->timeout)) {
 			EV_FD_SET(cfd, DIR_RD);
 			tv_add(&s->req->rex, &now, &s->req->rto);
-			tv_add(&s->rep->wex, &now, &s->rep->wto);
 			t->expire = s->req->rex;
 		}
 
@@ -1305,8 +1307,8 @@
 /* Processes data exchanges on the statistics socket. The client processing
  * is called and the task is put back in the wait queue or it is cleared.
  * In order to ease the transition, we simply simulate the server status
- * for now. It only knows states SV_STIDLE and SV_STCLOSE. Returns in <next>
- * the task's expiration date.
+ * for now. It only knows states SV_STIDLE, SV_STDATA and SV_STCLOSE. Returns
+ * in <next> the task's expiration date.
  */
 void process_uxst_stats(struct task *t, struct timeval *next)
 {
@@ -1314,40 +1316,51 @@
 	struct listener *listener;
 	int fsm_resync = 0;
 
+	/* we need to be in DATA phase on the "server" side */
+	if (s->srv_state == SV_STIDLE) {
+		s->srv_state = SV_STDATA;
+		s->data_source = DATA_SRC_STATS;
+	}
+			
 	do {
-		//fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
-		fsm_resync = 0;
-		fsm_resync |= process_uxst_cli(s);
-		if (s->srv_state == SV_STIDLE) {
-			if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
-				s->srv_state = SV_STCLOSE;
-				fsm_resync |= 1;
-				continue;
-			}
-			else if (s->cli_state == CL_STSHUTR ||
-				 (s->req->l >= s->req->rlim - s->req->data)) {
-				if (s->req->l == 0) {
+		fsm_resync = process_uxst_cli(s);
+		if (s->srv_state != SV_STDATA)
+			continue;
+
+		if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
+			s->srv_state = SV_STCLOSE;
+			fsm_resync |= 1;
+			continue;
+		}
+
+		if (s->data_state == DATA_ST_INIT) {
+			if ((s->req->l >= 10) && (memcmp(s->req->data, "show stat\n", 10) == 0)) {
+				/* send the stats, and changes the data_state */
+				if (stats_dump_raw(s, NULL, 0) != 0) {
 					s->srv_state = SV_STCLOSE;
 					fsm_resync |= 1;
 					continue;
 				}
-				/* OK we have some remaining data to process. Just for the
-				 * sake of an exercice, we copy the req into the resp,
-				 * and flush the req. This produces a simple echo function.
-				 */
-				memcpy(s->rep->data, s->req->data, sizeof(s->rep->data));
-				s->rep->l = s->req->l;
-				s->rep->rlim = s->rep->data + BUFSIZE;
-				s->rep->w = s->rep->data;
-				s->rep->lr = s->rep->r = s->rep->data + s->rep->l;
-
-				s->req->l = 0;
+			}
+			else if (s->cli_state == CL_STSHUTR || (s->req->l >= s->req->rlim - s->req->data)) {
 				s->srv_state = SV_STCLOSE;
-
 				fsm_resync |= 1;
 				continue;
 			}
 		}
+
+		if (s->data_state == DATA_ST_INIT)
+			continue;
+
+		/* OK we have some remaining data to process. Just for the
+		 * sake of an exercice, we copy the req into the resp,
+		 * and flush the req. This produces a simple echo function.
+		 */
+		if (stats_dump_raw(s, NULL, 0) != 0) {
+			s->srv_state = SV_STCLOSE;
+			fsm_resync |= 1;
+			continue;
+		}
 	} while (fsm_resync);
 
 	if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
@@ -1414,7 +1427,6 @@
 static void __uxst_protocol_init(void)
 {
 	protocol_register(&proto_unix);
-	//tv_eternity(&global.unix_fe.clitimeout);
 }