[MEDIUM] fix stats socket limitation to 16 kB

Due to the way the stats socket work, it was not possible to
maintain the information related to the command entered, so
after filling a whole buffer, the request was lost and it was
considered that there was nothing to write anymore.

The major reason was that some flags were passed directly
during the first call to stats_dump_raw() instead of being
stored persistently in the session.

To definitely fix this problem, flags were added to the stats
member of the session structure.

A second problem appeared. When the stats were produced, a first
call to client_retnclose() was performed, then one or multiple
subsequent calls to buffer_write_chunks() were done. But once the
stats buffer was full and a reschedule operated, the buffer was
flushed, the write flag cleared from the buffer and nothing was
done to re-arm it.

For this reason, a check was added in the proto_uxst_stats()
function in order to re-call the client FSM when data were added
by stats_dump_raw(). Finally, the whole unix stats dump FSM was
rewritten to avoid all the magics it depended on. It is now
simpler and looks more like the HTTP one.
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index 76709c1..556649c 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -1356,38 +1356,39 @@
 /* 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, SV_STDATA and SV_STCLOSE. Returns
- * in <next> the task's expiration date.
+ * for now. It only knows states SV_STIDLE, SV_STCONN, SV_STDATA, and
+ * SV_STCLOSE. Returns in <next> the task's expiration date.
  */
 void process_uxst_stats(struct task *t, struct timeval *next)
 {
 	struct session *s = t->context;
 	struct listener *listener;
 	int fsm_resync = 0;
+	int last_rep_l;
 
-	/* 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 {
+		char *args[MAX_UXST_ARGS + 1];
+		char *line, *p;
+		int arg;
+
 		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;
+			break;
 		}
 
-		if (s->data_state == DATA_ST_INIT) {
-
-			char *args[MAX_UXST_ARGS + 1];
-			char *line, *p;
-			int arg;
+		switch (s->srv_state) {
+		case SV_STIDLE:
+			/* stats output not initialized yet */
+			memset(&s->data_ctx.stats, 0, sizeof(s->data_ctx.stats));
+			s->data_source = DATA_SRC_STATS;
+			s->srv_state = SV_STCONN;
+			fsm_resync |= 1;
+			break;
 
+		case SV_STCONN: /* will change to SV_STANALYZE */
+			/* stats initialized, but waiting for the command */
 			line = s->req->data;
 			p = memchr(line, '\n', s->req->l);
 
@@ -1422,28 +1423,24 @@
 			if (!strcmp(args[0], "show")) {
 				if (!strcmp(args[1], "stat")) {
 					if (*args[2] && *args[3] && *args[4]) {
-						s->flags |= SN_STAT_BOUND;
+						s->data_ctx.stats.flags |= STAT_BOUND;
 						s->data_ctx.stats.iid	= atoi(args[2]);
 						s->data_ctx.stats.type	= atoi(args[3]);
 						s->data_ctx.stats.sid	= atoi(args[4]);
 					}
 
-					/* send the stats, and changes the data_state */
-					if (stats_dump_raw(s, NULL, STAT_SHOW_STAT) != 0) {
-						s->srv_state = SV_STCLOSE;
-						fsm_resync |= 1;
-					}
-
+					s->data_ctx.stats.flags |= STAT_SHOW_STAT;
+					s->data_ctx.stats.flags |= STAT_FMT_CSV;
+					s->srv_state = SV_STDATA;
+					fsm_resync |= 1;
 					continue;
 				}
 
 				if (!strcmp(args[1], "info")) {
-					/* send the stats, and changes the data_state */
-					if (stats_dump_raw(s, NULL, STAT_SHOW_INFO) != 0) {
-						s->srv_state = SV_STCLOSE;
-						fsm_resync |= 1;
-					}
-
+					s->data_ctx.stats.flags |= STAT_SHOW_INFO;
+					s->data_ctx.stats.flags |= STAT_FMT_CSV;
+					s->srv_state = SV_STDATA;
+					fsm_resync |= 1;
 					continue;
 				}
 			}
@@ -1451,16 +1448,21 @@
 			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.
-		 */
-		if (stats_dump_raw(s, NULL, 0) != 0) {
-			s->srv_state = SV_STCLOSE;
-			fsm_resync |= 1;
-			continue;
+		case SV_STDATA:
+			/* OK we have to process the request. Since it is possible
+			 * that we get there with the client output paused, we
+			 * will simply check that we have really sent some data
+			 * and wake the client up if needed.
+			 */
+			last_rep_l = s->rep->l;
+			if (stats_dump_raw(s, NULL) != 0) {
+				s->srv_state = SV_STCLOSE;
+				fsm_resync |= 1;
+			}
+			if (s->rep->l != last_rep_l)
+				fsm_resync |= 1;
+			break;
 		}
 	} while (fsm_resync);