MAJOR: cli: Update the CLI applet to handle its own buffers

It is the third applet to be refactored to use its own buffers. In addition to
the CLI applet, some I/O handlers of CLI commands were also updated, especially
the stats ones.

Some command I/O handlers were updated to use applet's buffers instead of
channels ones.
This commit is contained in:
Christopher Faulet 2024-02-15 13:34:05 +01:00
parent b8ca114031
commit f37ddbeb4b
4 changed files with 58 additions and 47 deletions

View File

@ -910,34 +910,36 @@ static int cli_output_msg(struct appctx *appctx, const char *msg, int severity,
*/ */
static void cli_io_handler(struct appctx *appctx) static void cli_io_handler(struct appctx *appctx)
{ {
struct stconn *sc = appctx_sc(appctx);
struct channel *res = sc_ic(sc);
struct bind_conf *bind_conf = strm_li(__sc_strm(sc))->bind_conf;
int reql; int reql;
int len; int len;
int lf = 0; int lf = 0;
if (unlikely(se_fl_test(appctx->sedesc, (SE_FL_EOS|SE_FL_ERROR)))) { if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL))
co_skip(sc_oc(sc), co_data(sc_oc(sc))); goto out;
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
applet_fl_set(appctx, APPCTX_FL_OUTBLK_ALLOC);
goto out; goto out;
} }
/* Check if the input buffer is available. */ if (unlikely(applet_fl_test(appctx, APPCTX_FL_EOS|APPCTX_FL_ERROR))) {
if (!b_size(&res->buf)) { appctx->st0 = CLI_ST_END;
sc_need_room(sc, 0);
goto out; goto out;
} }
while (1) { while (1) {
if (appctx->st0 == CLI_ST_INIT) { if (appctx->st0 == CLI_ST_INIT) {
/* reset severity to default at init */ /* reset severity to default at init */
struct stconn *sc = appctx_sc(appctx);
struct bind_conf *bind_conf = strm_li(__sc_strm(sc))->bind_conf;
appctx->cli_severity_output = bind_conf->severity_output; appctx->cli_severity_output = bind_conf->severity_output;
applet_reset_svcctx(appctx); applet_reset_svcctx(appctx);
appctx->st0 = CLI_ST_GETREQ; appctx->st0 = CLI_ST_GETREQ;
appctx->cli_level = bind_conf->level; appctx->cli_level = bind_conf->level;
} }
else if (appctx->st0 == CLI_ST_END) { else if (appctx->st0 == CLI_ST_END) {
se_fl_set(appctx->sedesc, SE_FL_EOS); applet_set_eos(appctx);
free_trash_chunk(appctx->chunk); free_trash_chunk(appctx->chunk);
appctx->chunk = NULL; appctx->chunk = NULL;
break; break;
@ -960,8 +962,8 @@ static void cli_io_handler(struct appctx *appctx)
/* ensure we have some output room left in the event we /* ensure we have some output room left in the event we
* would want to return some info right after parsing. * would want to return some info right after parsing.
*/ */
if (buffer_almost_full(sc_ib(sc))) { if (buffer_almost_full(&appctx->outbuf)) {
sc_need_room(sc, b_size(&res->buf) / 2); applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL);
break; break;
} }
@ -972,19 +974,30 @@ static void cli_io_handler(struct appctx *appctx)
*/ */
if (appctx->st1 & APPCTX_CLI_ST1_PAYLOAD) if (appctx->st1 & APPCTX_CLI_ST1_PAYLOAD)
reql = co_getline(sc_oc(sc), str, reql = b_getline(&appctx->inbuf, 0, b_data(&appctx->inbuf), str,
appctx->chunk->size - appctx->chunk->data - 1); appctx->chunk->size - appctx->chunk->data - 1);
else else
reql = co_getdelim(sc_oc(sc), str, reql = b_getdelim(&appctx->inbuf, 0, b_data(&appctx->inbuf), str,
appctx->chunk->size - appctx->chunk->data - 1, appctx->chunk->size - appctx->chunk->data - 1,
"\n;", '\\'); "\n;", '\\');
if (reql <= 0) { /* closed or EOL not found */ if (!reql) {
if (reql == 0) /* Line not found. Report an error if the input buffer is full, if there is not
break; * enough space in the chunk or if a shutdown occurred.
se_fl_set(appctx->sedesc, SE_FL_ERROR); * Otherwise, wait for more data */
appctx->st0 = CLI_ST_END; if (applet_fl_test(appctx, APPCTX_FL_INBLK_FULL) ||
continue; b_data(&appctx->inbuf) > appctx->chunk->size - appctx->chunk->data - 1) {
applet_set_eos(appctx);
applet_set_error(appctx);
cli_err(appctx, "The command is too big for the buffer size. Please change tune.bufsize in the configuration to use a bigger command.\n");
goto cli_output;
}
if (se_fl_test(appctx->sedesc, SE_FL_SHW)) {
applet_set_error(appctx);
appctx->st0 = CLI_ST_END;
continue;
}
break;
} }
if (str[reql-1] == '\n') if (str[reql-1] == '\n')
@ -996,12 +1009,8 @@ static void cli_io_handler(struct appctx *appctx)
*/ */
len = reql - 1; len = reql - 1;
if (str[len] != '\n' && str[len] != ';') { if (str[len] != '\n' && str[len] != ';') {
se_fl_set(appctx->sedesc, SE_FL_ERROR); applet_set_eos(appctx);
if (reql == appctx->chunk->size - appctx->chunk->data - 1) { applet_set_error(appctx);
cli_err(appctx, "The command is too big for the buffer size. Please change tune.bufsize in the configuration to use a bigger command.\n");
co_skip(sc_oc(sc), co_data(sc_oc(sc)));
goto cli_output;
}
appctx->st0 = CLI_ST_END; appctx->st0 = CLI_ST_END;
continue; continue;
} }
@ -1082,8 +1091,7 @@ static void cli_io_handler(struct appctx *appctx)
} }
/* re-adjust req buffer */ /* re-adjust req buffer */
co_skip(sc_oc(sc), reql); b_del(&appctx->inbuf, reql);
sc_opposite(sc)->flags |= SC_FL_RCV_ONCE; /* we plan to read small requests */
} }
else { /* output functions */ else { /* output functions */
struct cli_print_ctx *ctx; struct cli_print_ctx *ctx;
@ -1205,10 +1213,10 @@ static void cli_io_handler(struct appctx *appctx)
* non-interactive mode. * non-interactive mode.
*/ */
if ((appctx->st1 & (APPCTX_CLI_ST1_PROMPT|APPCTX_CLI_ST1_PAYLOAD|APPCTX_CLI_ST1_LASTCMD)) == APPCTX_CLI_ST1_LASTCMD) { if ((appctx->st1 & (APPCTX_CLI_ST1_PROMPT|APPCTX_CLI_ST1_PAYLOAD|APPCTX_CLI_ST1_LASTCMD)) == APPCTX_CLI_ST1_LASTCMD) {
se_fl_set(appctx->sedesc, SE_FL_EOI); applet_set_eoi(appctx);
appctx->st0 = CLI_ST_END; appctx->st0 = CLI_ST_END;
continue; continue;
} }
/* switch state back to GETREQ to read next requests */ /* switch state back to GETREQ to read next requests */
applet_reset_svcctx(appctx); applet_reset_svcctx(appctx);
@ -1225,7 +1233,7 @@ static void cli_io_handler(struct appctx *appctx)
* refills the buffer with new bytes in non-interactive * refills the buffer with new bytes in non-interactive
* mode, avoiding to close on apparently empty commands. * mode, avoiding to close on apparently empty commands.
*/ */
if (co_data(sc_oc(sc))) { if (b_data(&appctx->inbuf)) {
appctx_wakeup(appctx); appctx_wakeup(appctx);
goto out; goto out;
} }
@ -1233,6 +1241,11 @@ static void cli_io_handler(struct appctx *appctx)
} }
out: out:
if (appctx->st0 == CLI_ST_END) {
/* eat the whole request */
b_reset(&appctx->inbuf);
applet_fl_clr(appctx, APPCTX_FL_INBLK_FULL);
}
return; return;
} }
@ -2131,7 +2144,7 @@ static int cli_io_handler_wait(struct appctx *appctx)
wait: wait:
/* Stop waiting upon close/abort/error */ /* Stop waiting upon close/abort/error */
if (unlikely(se_fl_test(appctx->sedesc, SE_FL_SHW))) { if (unlikely(se_fl_test(appctx->sedesc, SE_FL_SHW)) && !b_data(&appctx->inbuf)) {
ctx->error = CLI_WAIT_ERR_INTR; ctx->error = CLI_WAIT_ERR_INTR;
return 1; return 1;
} }
@ -2139,6 +2152,7 @@ static int cli_io_handler_wait(struct appctx *appctx)
return 0; return 0;
} }
/* release structs allocated by "delete server" */ /* release structs allocated by "delete server" */
static void cli_release_wait(struct appctx *appctx) static void cli_release_wait(struct appctx *appctx)
{ {
@ -3523,6 +3537,8 @@ static struct applet cli_applet = {
.obj_type = OBJ_TYPE_APPLET, .obj_type = OBJ_TYPE_APPLET,
.name = "<CLI>", /* used for logging */ .name = "<CLI>", /* used for logging */
.fct = cli_io_handler, .fct = cli_io_handler,
.rcv_buf = appctx_raw_rcv_buf,
.snd_buf = appctx_raw_snd_buf,
.release = cli_release_handler, .release = cli_release_handler,
}; };
@ -3531,6 +3547,8 @@ static struct applet mcli_applet = {
.obj_type = OBJ_TYPE_APPLET, .obj_type = OBJ_TYPE_APPLET,
.name = "<MCLI>", /* used for logging */ .name = "<MCLI>", /* used for logging */
.fct = cli_io_handler, .fct = cli_io_handler,
.rcv_buf = appctx_raw_rcv_buf,
.snd_buf = appctx_raw_snd_buf,
.release = cli_release_handler, .release = cli_release_handler,
}; };

View File

@ -190,7 +190,6 @@ err:
static int hc_cli_io_handler(struct appctx *appctx) static int hc_cli_io_handler(struct appctx *appctx)
{ {
struct hcli_svc_ctx *ctx = appctx->svcctx; struct hcli_svc_ctx *ctx = appctx->svcctx;
struct stconn *sc = appctx_sc(appctx);
struct httpclient *hc = ctx->hc; struct httpclient *hc = ctx->hc;
struct http_hdr *hdrs, *hdr; struct http_hdr *hdrs, *hdr;
@ -217,10 +216,7 @@ static int hc_cli_io_handler(struct appctx *appctx)
} }
if (ctx->flags & HC_F_RES_BODY) { if (ctx->flags & HC_F_RES_BODY) {
int ret; httpclient_res_xfer(hc, &appctx->outbuf);
ret = httpclient_res_xfer(hc, sc_ib(sc));
channel_add_input(sc_ic(sc), ret); /* forward what we put in the buffer channel */
/* remove the flag if the buffer was emptied */ /* remove the flag if the buffer was emptied */
if (httpclient_data(hc)) if (httpclient_data(hc))

View File

@ -3177,7 +3177,6 @@ static int cli_parse_show_errors(char **args, char *payload, struct appctx *appc
static int cli_io_handler_show_errors(struct appctx *appctx) static int cli_io_handler_show_errors(struct appctx *appctx)
{ {
struct show_errors_ctx *ctx = appctx->svcctx; struct show_errors_ctx *ctx = appctx->svcctx;
struct stconn *sc = appctx_sc(appctx);
extern const char *monthname[12]; extern const char *monthname[12];
chunk_reset(&trash); chunk_reset(&trash);
@ -3309,7 +3308,7 @@ static int cli_io_handler_show_errors(struct appctx *appctx)
newline = ctx->bol; newline = ctx->bol;
newptr = dump_text_line(&trash, es->buf, global.tune.bufsize, es->buf_len, &newline, ctx->ptr); newptr = dump_text_line(&trash, es->buf, global.tune.bufsize, es->buf_len, &newline, ctx->ptr);
if (newptr == ctx->ptr) { if (newptr == ctx->ptr) {
sc_need_room(sc, 0); applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL);
goto cant_send_unlock; goto cant_send_unlock;
} }

View File

@ -346,10 +346,8 @@ int stats_is_full(struct appctx *appctx, struct buffer *buf, struct htx *htx)
} }
} }
else { else {
struct channel *rep = sc_ic(appctx_sc(appctx)); if (buffer_almost_full(&appctx->outbuf)) {
applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL);
if (buffer_almost_full(&rep->buf)) {
sc_need_room(appctx_sc(appctx), b_size(&rep->buf) / 2);
goto full; goto full;
} }
} }