src/dumpstats.c
static void cli_io_handler(struct stream_interface *si)
{
	struct channel *req = si->ob;
	struct channel *res = si->ib;
	int reql;
	int len;

	if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
		goto out;

	while (1) {
		if (si->applet.st0 == STAT_CLI_INIT) {
			/* Stats output not initialized yet */
			memset(&si->applet.ctx.stats, 0, sizeof(si->applet.ctx.stats));
			si->applet.st0 = STAT_CLI_GETREQ;
		}
		else if (si->applet.st0 == STAT_CLI_END) {
			/* Let's close for real now. We just close the request
			 * side, the conditions below will complete if needed.
			 */
			si_shutw(si);
			break;
		}
		else if (si->applet.st0 == STAT_CLI_GETREQ) {
			/* ensure we have some output room left in the event we
			 * would want to return some info right after parsing.
			 */
			if (buffer_almost_full(si->ib->buf))
				break;

			reql = bo_getline(si->ob, trash.str, trash.size);
			if (reql <= 0) { /* closed or EOL not found */
				if (reql == 0)
					break;
				si->applet.st0 = STAT_CLI_END;
				continue;
			}

			/* seek for a possible semi-colon. If we find one, we
			 * replace it with an LF and skip only this part.
			 */
			for (len = 0; len < reql; len++)
				if (trash.str[len] == ';') {
					trash.str[len] = '\n';
					reql = len + 1;
					break;
				}

			/* now it is time to check that we have a full line,
			 * remove the trailing \n and possibly \r, then cut the
			 * line.
			 */
			len = reql - 1;
			if (trash.str[len] != '\n') {
				si->applet.st0 = STAT_CLI_END;
				continue;
			}

			if (len && trash.str[len-1] == '\r')
				len--;

			trash.str[len] = '\0';

			si->applet.st0 = STAT_CLI_PROMPT;
			if (len) {
				if (strcmp(trash.str, "quit") == 0) {
					si->applet.st0 = STAT_CLI_END;
					continue;
				}
				else if (strcmp(trash.str, "prompt") == 0)
					si->applet.st1 = !si->applet.st1;
				else if (strcmp(trash.str, "help") == 0 ||
					 !stats_sock_parse_request(si, trash.str)) {
					si->applet.ctx.cli.msg = stats_sock_usage_msg;
					si->applet.st0 = STAT_CLI_PRINT;
				}
				/* NB: stats_sock_parse_request() may have put
				 * another STAT_CLI_O_* into si->applet.st0.
				 */
			}
			else if (!si->applet.st1) {
				/* if prompt is disabled, print help on empty lines,
				 * so that the user at least knows how to enable
				 * prompt and find help.
				 */
				si->applet.ctx.cli.msg = stats_sock_usage_msg;
				si->applet.st0 = STAT_CLI_PRINT;
			}

			/* re-adjust req buffer */
			bo_skip(si->ob, reql);
			req->flags |= CF_READ_DONTWAIT; /* we plan to read small requests */
		}
		else {	/* output functions: first check if the output buffer is closed then abort */
			if (res->flags & (CF_SHUTR_NOW|CF_SHUTR)) {
				si->applet.st0 = STAT_CLI_END;
				continue;
			}

			switch (si->applet.st0) {
			case STAT_CLI_PRINT:
				if (bi_putstr(si->ib, si->applet.ctx.cli.msg) != -1)
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_INFO:
				if (stats_dump_info_to_buffer(si))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_STAT:
				if (stats_dump_stat_to_buffer(si, NULL))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_SESS:
				if (stats_dump_sess_to_buffer(si))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_ERR:	/* errors dump */
				if (stats_dump_errors_to_buffer(si))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_TAB:
			case STAT_CLI_O_CLR:
				if (stats_table_request(si, si->applet.st0))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			default: /* abnormal state */
				si->applet.st0 = STAT_CLI_PROMPT;
				break;
			}

			/* The post-command prompt is either LF alone or LF + '> ' in interactive mode */
			if (si->applet.st0 == STAT_CLI_PROMPT) {
				if (bi_putstr(si->ib, si->applet.st1 ? "\n> " : "\n") != -1)
					si->applet.st0 = STAT_CLI_GETREQ;
			}

			/* If the output functions are still there, it means they require more room. */
			if (si->applet.st0 >= STAT_CLI_OUTPUT)
				break;

			/* Now we close the output if one of the writers did so,
			 * or if we're not in interactive mode and the request
			 * buffer is empty. This still allows pipelined requests
			 * to be sent in non-interactive mode.
			 */
			if ((res->flags & (CF_SHUTW|CF_SHUTW_NOW)) || (!si->applet.st1 && !req->buf->o)) {
				si->applet.st0 = STAT_CLI_END;
				continue;
			}

			/* switch state back to GETREQ to read next requests */
			si->applet.st0 = STAT_CLI_GETREQ;
		}
	}

	if ((res->flags & CF_SHUTR) && (si->state == SI_ST_EST) && (si->applet.st0 != STAT_CLI_GETREQ)) {
		DPRINTF(stderr, "%s@%d: si to buf closed. req=%08x, res=%08x, st=%d\n",
			__FUNCTION__, __LINE__, req->flags, res->flags, si->state);
		/* Other side has closed, let's abort if we have no more processing to do
		 * and nothing more to consume. This is comparable to a broken pipe, so
		 * we forward the close to the request side so that it flows upstream to
		 * the client.
		 */
		si_shutw(si);
	}

	if ((req->flags & CF_SHUTW) && (si->state == SI_ST_EST) && (si->applet.st0 < STAT_CLI_OUTPUT)) {
		DPRINTF(stderr, "%s@%d: buf to si closed. req=%08x, res=%08x, st=%d\n",
			__FUNCTION__, __LINE__, req->flags, res->flags, si->state);
		/* We have no more processing to do, and nothing more to send, and
		 * the client side has closed. So we'll forward this state downstream
		 * on the response buffer.
		 */
		si_shutr(si);
		res->flags |= CF_READ_NULL;
	}

	/* update all other flags and resync with the other side */
	si_update(si);

	/* we don't want to expire timeouts while we're processing requests */
	si->ib->rex = TICK_ETERNITY;
	si->ob->wex = TICK_ETERNITY;

 out:
	DPRINTF(stderr, "%s@%d: st=%d, rqf=%x, rpf=%x, rqh=%d, rqs=%d, rh=%d, rs=%d\n",
		__FUNCTION__, __LINE__,
		si->state, req->flags, res->flags, req->buf->i, req->buf->o, res->buf->i, res->buf->o);

	if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) {
		/* check that we have released everything then unregister */
		stream_int_unregister_handler(si);
	}
}
/* This I/O handler runs as an applet embedded in a stream interface. It is
 * used to processes I/O from/to the stats unix socket. The system relies on a
 * state machine handling requests and various responses. We read a request,
 * then we process it and send the response, and we possibly display a prompt.
 * Then we can read again. The state is stored in si->applet.st0 and is one of the
 * STAT_CLI_* constants. si->applet.st1 is used to indicate whether prompt is enabled
 * or not.
 */
This I/O handler runs as an applet embedded in a stream interface. It is
used to processes I/O from/to the stats unix socket. The system relies on a
state machine handling requests and various responses. We read a request,
then we process it and send the response, and we possibly display a prompt.
Then we can read again. The state is stored in si->applet.st0 and is one of the
STAT_CLI_* constants. si->applet.st1 is used to indicate whether prompt is enabled
or not.
This I / O handler runs as an applet embedded in a stream interface . It is used to processes I / O from / to the stats unix socket . The system relies on a state machine handling requests and various responses . We read a request then we process it and send the response and we possibly display a prompt . Then we can read again . The state is stored in si - > applet . st0 and is one of the STAT_CLI_ * constants . si - > applet . st1 is used to indicate whether prompt is enabled or not .
static void cli_io_handler(struct stream_interface *si)
{
	struct channel *req = si->ob;
	struct channel *res = si->ib;
	int reql;
	int len;
	if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
		goto out;
	while (1) {
		if (si->applet.st0 == STAT_CLI_INIT) {
			memset(&si->applet.ctx.stats, 0, sizeof(si->applet.ctx.stats));
			si->applet.st0 = STAT_CLI_GETREQ;
		}
		else if (si->applet.st0 == STAT_CLI_END) {
			si_shutw(si);
			break;
		}
		else if (si->applet.st0 == STAT_CLI_GETREQ) {
			if (buffer_almost_full(si->ib->buf))
				break;
			reql = bo_getline(si->ob, trash.str, trash.size);
			if (reql <= 0) { 
				if (reql == 0)
					break;
				si->applet.st0 = STAT_CLI_END;
				continue;
			}
			for (len = 0; len < reql; len++)
				if (trash.str[len] == ';') {
					trash.str[len] = '\n';
					reql = len + 1;
					break;
				}
			len = reql - 1;
			if (trash.str[len] != '\n') {
				si->applet.st0 = STAT_CLI_END;
				continue;
			}
			if (len && trash.str[len-1] == '\r')
				len--;
			trash.str[len] = '\0';
			si->applet.st0 = STAT_CLI_PROMPT;
			if (len) {
				if (strcmp(trash.str, "quit") == 0) {
					si->applet.st0 = STAT_CLI_END;
					continue;
				}
				else if (strcmp(trash.str, "prompt") == 0)
					si->applet.st1 = !si->applet.st1;
				else if (strcmp(trash.str, "help") == 0 ||
					 !stats_sock_parse_request(si, trash.str)) {
					si->applet.ctx.cli.msg = stats_sock_usage_msg;
					si->applet.st0 = STAT_CLI_PRINT;
				}
			}
			else if (!si->applet.st1) {
				si->applet.ctx.cli.msg = stats_sock_usage_msg;
				si->applet.st0 = STAT_CLI_PRINT;
			}
			bo_skip(si->ob, reql);
			req->flags |= CF_READ_DONTWAIT; 
		}
		else {	
			if (res->flags & (CF_SHUTR_NOW|CF_SHUTR)) {
				si->applet.st0 = STAT_CLI_END;
				continue;
			}
			switch (si->applet.st0) {
			case STAT_CLI_PRINT:
				if (bi_putstr(si->ib, si->applet.ctx.cli.msg) != -1)
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_INFO:
				if (stats_dump_info_to_buffer(si))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_STAT:
				if (stats_dump_stat_to_buffer(si, NULL))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_SESS:
				if (stats_dump_sess_to_buffer(si))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_ERR:	
				if (stats_dump_errors_to_buffer(si))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			case STAT_CLI_O_TAB:
			case STAT_CLI_O_CLR:
				if (stats_table_request(si, si->applet.st0))
					si->applet.st0 = STAT_CLI_PROMPT;
				break;
			default: 
				si->applet.st0 = STAT_CLI_PROMPT;
				break;
			}
			if (si->applet.st0 == STAT_CLI_PROMPT) {
				if (bi_putstr(si->ib, si->applet.st1 ? "\n> " : "\n") != -1)
					si->applet.st0 = STAT_CLI_GETREQ;
			}
			if (si->applet.st0 >= STAT_CLI_OUTPUT)
				break;
			if ((res->flags & (CF_SHUTW|CF_SHUTW_NOW)) || (!si->applet.st1 && !req->buf->o)) {
				si->applet.st0 = STAT_CLI_END;
				continue;
			}
			si->applet.st0 = STAT_CLI_GETREQ;
		}
	}
	if ((res->flags & CF_SHUTR) && (si->state == SI_ST_EST) && (si->applet.st0 != STAT_CLI_GETREQ)) {
		DPRINTF(stderr, "%s@%d: si to buf closed. req=%08x, res=%08x, st=%d\n",
			__FUNCTION__, __LINE__, req->flags, res->flags, si->state);
		si_shutw(si);
	}
	if ((req->flags & CF_SHUTW) && (si->state == SI_ST_EST) && (si->applet.st0 < STAT_CLI_OUTPUT)) {
		DPRINTF(stderr, "%s@%d: buf to si closed. req=%08x, res=%08x, st=%d\n",
			__FUNCTION__, __LINE__, req->flags, res->flags, si->state);
		si_shutr(si);
		res->flags |= CF_READ_NULL;
	}
	si_update(si);
	si->ib->rex = TICK_ETERNITY;
	si->ob->wex = TICK_ETERNITY;
 out:
	DPRINTF(stderr, "%s@%d: st=%d, rqf=%x, rpf=%x, rqh=%d, rqs=%d, rh=%d, rs=%d\n",
		__FUNCTION__, __LINE__,
		si->state, req->flags, res->flags, req->buf->i, req->buf->o, res->buf->i, res->buf->o);
	if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) {
		stream_int_unregister_handler(si);
	}
}
static void cli_io_handler ( struct stream_interface * si ) { struct channel * req = si -> ob ; struct channel * res = si -> ib ; int reql ; int len ; if ( unlikely ( si -> state == SI_ST_DIS || si -> state == SI_ST_CLO ) ) goto out ; while ( 1 ) { if ( si -> applet . st0 == STAT_CLI_INIT ) { memset ( & si -> applet . ctx . stats , 0 , sizeof ( si -> applet . ctx . stats ) ) ; si -> applet . st0 = STAT_CLI_GETREQ ; } else if ( si -> applet . st0 == STAT_CLI_END ) { si_shutw ( si ) ; break ; } else if ( si -> applet . st0 == STAT_CLI_GETREQ ) { if ( buffer_almost_full ( si -> ib -> buf ) ) break ; reql = bo_getline ( si -> ob , trash . str , trash . size ) ; if ( reql <= 0 ) { if ( reql == 0 ) break ; si -> applet . st0 = STAT_CLI_END ; continue ; } for ( len = 0 ; len < reql ; len ++ ) if ( trash . str [ len ] == ' ' ) { trash . str [ len ] = ' \n ' ; reql = len + 1 ; break ; } len = reql - 1 ; if ( trash . str [ len ] != ' \n ' ) { si -> applet . st0 = STAT_CLI_END ; continue ; } if ( len && trash . str [ len - 1 ] == ' \r ' ) len -- ; trash . str [ len ] = ' \0 ' ; si -> applet . st0 = STAT_CLI_PROMPT ; if ( len ) { if ( strcmp ( trash . str , " " ) == 0 ) { si -> applet . st0 = STAT_CLI_END ; continue ; } else if ( strcmp ( trash . str , " " ) == 0 ) si -> applet . st1 = ! si -> applet . st1 ; else if ( strcmp ( trash . str , " " ) == 0 || ! stats_sock_parse_request ( si , trash . str ) ) { si -> applet . ctx . cli . msg = stats_sock_usage_msg ; si -> applet . st0 = STAT_CLI_PRINT ; } } else if ( ! si -> applet . st1 ) { si -> applet . ctx . cli . msg = stats_sock_usage_msg ; si -> applet . st0 = STAT_CLI_PRINT ; } bo_skip ( si -> ob , reql ) ; req -> flags |= CF_READ_DONTWAIT ; } else { if ( res -> flags & ( CF_SHUTR_NOW | CF_SHUTR ) ) { si -> applet . st0 = STAT_CLI_END ; continue ; } switch ( si -> applet . st0 ) { case STAT_CLI_PRINT : if ( bi_putstr ( si -> ib , si -> applet . ctx . cli . msg ) != -1 ) si -> applet . st0 = STAT_CLI_PROMPT ; break ; case STAT_CLI_O_INFO : if ( stats_dump_info_to_buffer ( si ) ) si -> applet . st0 = STAT_CLI_PROMPT ; break ; case STAT_CLI_O_STAT : if ( stats_dump_stat_to_buffer ( si , NULL ) ) si -> applet . st0 = STAT_CLI_PROMPT ; break ; case STAT_CLI_O_SESS : if ( stats_dump_sess_to_buffer ( si ) ) si -> applet . st0 = STAT_CLI_PROMPT ; break ; case STAT_CLI_O_ERR : if ( stats_dump_errors_to_buffer ( si ) ) si -> applet . st0 = STAT_CLI_PROMPT ; break ; case STAT_CLI_O_TAB : case STAT_CLI_O_CLR : if ( stats_table_request ( si , si -> applet . st0 ) ) si -> applet . st0 = STAT_CLI_PROMPT ; break ; default : si -> applet . st0 = STAT_CLI_PROMPT ; break ; } if ( si -> applet . st0 == STAT_CLI_PROMPT ) { if ( bi_putstr ( si -> ib , si -> applet . st1 ? " \n " : " \n " ) != -1 ) si -> applet . st0 = STAT_CLI_GETREQ ; } if ( si -> applet . st0 >= STAT_CLI_OUTPUT ) break ; if ( ( res -> flags & ( CF_SHUTW | CF_SHUTW_NOW ) ) || ( ! si -> applet . st1 && ! req -> buf -> o ) ) { si -> applet . st0 = STAT_CLI_END ; continue ; } si -> applet . st0 = STAT_CLI_GETREQ ; } } if ( ( res -> flags & CF_SHUTR ) && ( si -> state == SI_ST_EST ) && ( si -> applet . st0 != STAT_CLI_GETREQ ) ) { DPRINTF ( stderr , " \n " , __FUNCTION__ , __LINE__ , req -> flags , res -> flags , si -> state ) ; si_shutw ( si ) ; } if ( ( req -> flags & CF_SHUTW ) && ( si -> state == SI_ST_EST ) && ( si -> applet . st0 < STAT_CLI_OUTPUT ) ) { DPRINTF ( stderr , " \n " , __FUNCTION__ , __LINE__ , req -> flags , res -> flags , si -> state ) ; si_shutr ( si ) ; res -> flags |= CF_READ_NULL ; } si_update ( si ) ; si -> ib -> rex = TICK_ETERNITY ; si -> ob -> wex = TICK_ETERNITY ; out : DPRINTF ( stderr , " \n " , __FUNCTION__ , __LINE__ , si -> state , req -> flags , res -> flags , req -> buf -> i , req -> buf -> o , res -> buf -> i , res -> buf -> o ) ; if ( unlikely ( si -> state == SI_ST_DIS || si -> state == SI_ST_CLO ) ) { stream_int_unregister_handler ( si ) ; } }
This I/O handler runs as an applet embedded in a stream interface.
This I / O handler runs as an applet embedded in a stream interface .
/* Stats output not initialized yet */ /* Let's close for real now. We just close the request
			 * side, the conditions below will complete if needed.
			 */ /* ensure we have some output room left in the event we
			 * would want to return some info right after parsing.
			 */ /* closed or EOL not found */ /* seek for a possible semi-colon. If we find one, we
			 * replace it with an LF and skip only this part.
			 */ /* now it is time to check that we have a full line,
			 * remove the trailing \n and possibly \r, then cut the
			 * line.
			 */ /* NB: stats_sock_parse_request() may have put
				 * another STAT_CLI_O_* into si->applet.st0.
				 */ /* if prompt is disabled, print help on empty lines,
				 * so that the user at least knows how to enable
				 * prompt and find help.
				 */ /* re-adjust req buffer */ /* we plan to read small requests */ /* output functions: first check if the output buffer is closed then abort */ /* errors dump */ /* abnormal state */ /* The post-command prompt is either LF alone or LF + '> ' in interactive mode */ /* If the output functions are still there, it means they require more room. */ /* Now we close the output if one of the writers did so,
			 * or if we're not in interactive mode and the request
			 * buffer is empty. This still allows pipelined requests
			 * to be sent in non-interactive mode.
			 */ /* switch state back to GETREQ to read next requests */ /* Other side has closed, let's abort if we have no more processing to do
		 * and nothing more to consume. This is comparable to a broken pipe, so
		 * we forward the close to the request side so that it flows upstream to
		 * the client.
		 */ /* We have no more processing to do, and nothing more to send, and
		 * the client side has closed. So we'll forward this state downstream
		 * on the response buffer.
		 */ /* update all other flags and resync with the other side */ /* we don't want to expire timeouts while we're processing requests */ /* check that we have released everything then unregister */