From: Christopher Faulet Date: Thu, 15 Feb 2024 12:34:05 +0000 (+0100) Subject: MAJOR: cli: Update the CLI applet to handle its own buffers X-Git-Tag: v3.0-dev7~56 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f37ddbeb4b;p=thirdparty%2Fhaproxy.git 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. --- diff --git a/src/cli.c b/src/cli.c index 389f19efab..bbc1df4d94 100644 --- a/src/cli.c +++ b/src/cli.c @@ -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) { - 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 len; int lf = 0; - if (unlikely(se_fl_test(appctx->sedesc, (SE_FL_EOS|SE_FL_ERROR)))) { - co_skip(sc_oc(sc), co_data(sc_oc(sc))); + if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL)) + goto out; + + if (!appctx_get_buf(appctx, &appctx->outbuf)) { + applet_fl_set(appctx, APPCTX_FL_OUTBLK_ALLOC); goto out; } - /* Check if the input buffer is available. */ - if (!b_size(&res->buf)) { - sc_need_room(sc, 0); + if (unlikely(applet_fl_test(appctx, APPCTX_FL_EOS|APPCTX_FL_ERROR))) { + appctx->st0 = CLI_ST_END; goto out; } while (1) { if (appctx->st0 == CLI_ST_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; applet_reset_svcctx(appctx); appctx->st0 = CLI_ST_GETREQ; appctx->cli_level = bind_conf->level; } else if (appctx->st0 == CLI_ST_END) { - se_fl_set(appctx->sedesc, SE_FL_EOS); + applet_set_eos(appctx); free_trash_chunk(appctx->chunk); appctx->chunk = NULL; break; @@ -960,8 +962,8 @@ static void cli_io_handler(struct appctx *appctx) /* ensure we have some output room left in the event we * would want to return some info right after parsing. */ - if (buffer_almost_full(sc_ib(sc))) { - sc_need_room(sc, b_size(&res->buf) / 2); + if (buffer_almost_full(&appctx->outbuf)) { + applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL); break; } @@ -972,19 +974,30 @@ static void cli_io_handler(struct appctx *appctx) */ if (appctx->st1 & APPCTX_CLI_ST1_PAYLOAD) - reql = co_getline(sc_oc(sc), str, - appctx->chunk->size - appctx->chunk->data - 1); + reql = b_getline(&appctx->inbuf, 0, b_data(&appctx->inbuf), str, + appctx->chunk->size - appctx->chunk->data - 1); else - reql = co_getdelim(sc_oc(sc), str, - appctx->chunk->size - appctx->chunk->data - 1, - "\n;", '\\'); - - if (reql <= 0) { /* closed or EOL not found */ - if (reql == 0) - break; - se_fl_set(appctx->sedesc, SE_FL_ERROR); - appctx->st0 = CLI_ST_END; - continue; + reql = b_getdelim(&appctx->inbuf, 0, b_data(&appctx->inbuf), str, + appctx->chunk->size - appctx->chunk->data - 1, + "\n;", '\\'); + + if (!reql) { + /* Line not found. Report an error if the input buffer is full, if there is not + * enough space in the chunk or if a shutdown occurred. + * Otherwise, wait for more data */ + if (applet_fl_test(appctx, APPCTX_FL_INBLK_FULL) || + 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') @@ -996,12 +1009,8 @@ static void cli_io_handler(struct appctx *appctx) */ len = reql - 1; if (str[len] != '\n' && str[len] != ';') { - se_fl_set(appctx->sedesc, SE_FL_ERROR); - if (reql == appctx->chunk->size - appctx->chunk->data - 1) { - 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; - } + applet_set_eos(appctx); + applet_set_error(appctx); appctx->st0 = CLI_ST_END; continue; } @@ -1082,8 +1091,7 @@ static void cli_io_handler(struct appctx *appctx) } /* re-adjust req buffer */ - co_skip(sc_oc(sc), reql); - sc_opposite(sc)->flags |= SC_FL_RCV_ONCE; /* we plan to read small requests */ + b_del(&appctx->inbuf, reql); } else { /* output functions */ struct cli_print_ctx *ctx; @@ -1205,10 +1213,10 @@ static void cli_io_handler(struct appctx *appctx) * non-interactive mode. */ 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); - appctx->st0 = CLI_ST_END; - continue; - } + applet_set_eoi(appctx); + appctx->st0 = CLI_ST_END; + continue; + } /* switch state back to GETREQ to read next requests */ 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 * mode, avoiding to close on apparently empty commands. */ - if (co_data(sc_oc(sc))) { + if (b_data(&appctx->inbuf)) { appctx_wakeup(appctx); goto out; } @@ -1233,6 +1241,11 @@ static void cli_io_handler(struct appctx *appctx) } out: + if (appctx->st0 == CLI_ST_END) { + /* eat the whole request */ + b_reset(&appctx->inbuf); + applet_fl_clr(appctx, APPCTX_FL_INBLK_FULL); + } return; } @@ -2131,7 +2144,7 @@ static int cli_io_handler_wait(struct appctx *appctx) wait: /* 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; return 1; } @@ -2139,6 +2152,7 @@ static int cli_io_handler_wait(struct appctx *appctx) return 0; } + /* release structs allocated by "delete server" */ static void cli_release_wait(struct appctx *appctx) { @@ -3523,6 +3537,8 @@ static struct applet cli_applet = { .obj_type = OBJ_TYPE_APPLET, .name = "", /* used for logging */ .fct = cli_io_handler, + .rcv_buf = appctx_raw_rcv_buf, + .snd_buf = appctx_raw_snd_buf, .release = cli_release_handler, }; @@ -3531,6 +3547,8 @@ static struct applet mcli_applet = { .obj_type = OBJ_TYPE_APPLET, .name = "", /* used for logging */ .fct = cli_io_handler, + .rcv_buf = appctx_raw_rcv_buf, + .snd_buf = appctx_raw_snd_buf, .release = cli_release_handler, }; diff --git a/src/http_client.c b/src/http_client.c index 4d3415cf0c..e329954446 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -190,7 +190,6 @@ err: static int hc_cli_io_handler(struct appctx *appctx) { struct hcli_svc_ctx *ctx = appctx->svcctx; - struct stconn *sc = appctx_sc(appctx); struct httpclient *hc = ctx->hc; 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) { - int ret; - - ret = httpclient_res_xfer(hc, sc_ib(sc)); - channel_add_input(sc_ic(sc), ret); /* forward what we put in the buffer channel */ + httpclient_res_xfer(hc, &appctx->outbuf); /* remove the flag if the buffer was emptied */ if (httpclient_data(hc)) diff --git a/src/proxy.c b/src/proxy.c index 9adc6a2568..f87c3af2ef 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -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) { struct show_errors_ctx *ctx = appctx->svcctx; - struct stconn *sc = appctx_sc(appctx); extern const char *monthname[12]; chunk_reset(&trash); @@ -3309,7 +3308,7 @@ static int cli_io_handler_show_errors(struct appctx *appctx) newline = ctx->bol; newptr = dump_text_line(&trash, es->buf, global.tune.bufsize, es->buf_len, &newline, ctx->ptr); if (newptr == ctx->ptr) { - sc_need_room(sc, 0); + applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL); goto cant_send_unlock; } diff --git a/src/stats.c b/src/stats.c index 39e232591d..76fe2b70d5 100644 --- a/src/stats.c +++ b/src/stats.c @@ -346,10 +346,8 @@ int stats_is_full(struct appctx *appctx, struct buffer *buf, struct htx *htx) } } else { - struct channel *rep = sc_ic(appctx_sc(appctx)); - - if (buffer_almost_full(&rep->buf)) { - sc_need_room(appctx_sc(appctx), b_size(&rep->buf) / 2); + if (buffer_almost_full(&appctx->outbuf)) { + applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL); goto full; } }