diff --git a/src/resolvers.c b/src/resolvers.c index 7cbddef31..7d7ced6fd 100644 --- a/src/resolvers.c +++ b/src/resolvers.c @@ -2742,12 +2742,13 @@ static int cli_parse_stat_resolvers(char **args, char *payload, struct appctx *a /* Dumps counters from all resolvers section and associated name servers. It * returns 0 if the output buffer is full and it needs to be called again, * otherwise non-zero. It may limit itself to the resolver pointed to by - * if it's not null. + * if it's not null, and takes the current resolver section from p1 + * and the current resolver from p2. */ static int cli_io_handler_dump_resolvers_to_buffer(struct appctx *appctx) { struct conn_stream *cs = appctx->owner; - struct resolvers *resolvers; + struct resolvers *resolvers = appctx->ctx.cli.p1; struct dns_nameserver *ns; chunk_reset(&trash); @@ -2759,15 +2760,31 @@ static int cli_io_handler_dump_resolvers_to_buffer(struct appctx *appctx) case STAT_ST_LIST: if (LIST_ISEMPTY(&sec_resolvers)) { - chunk_appendf(&trash, "No resolvers found\n"); + if (ci_putstr(cs_ic(cs), "No resolvers found\n") == -1) + goto full; } else { - list_for_each_entry(resolvers, &sec_resolvers, list) { + if (!resolvers) + resolvers = LIST_ELEM(sec_resolvers.n, typeof(resolvers), list); + + list_for_each_entry_from(resolvers, &sec_resolvers, list) { if (appctx->ctx.cli.p0 != NULL && appctx->ctx.cli.p0 != resolvers) continue; - chunk_appendf(&trash, "Resolvers section %s\n", resolvers->id); - list_for_each_entry(ns, &resolvers->nameservers, list) { + appctx->ctx.cli.p1 = resolvers; + ns = appctx->ctx.cli.p2; + + if (!ns) { + chunk_printf(&trash, "Resolvers section %s\n", resolvers->id); + if (ci_putchk(cs_ic(cs), &trash) == -1) + goto full; + + ns = LIST_ELEM(resolvers->nameservers.n, typeof(ns), list); + appctx->ctx.cli.p2 = ns; + } + + list_for_each_entry_from(ns, &resolvers->nameservers, list) { + chunk_reset(&trash); chunk_appendf(&trash, " nameserver %s:\n", ns->id); chunk_appendf(&trash, " sent: %lld\n", ns->counters->sent); chunk_appendf(&trash, " snd_error: %lld\n", ns->counters->snd_error); @@ -2784,25 +2801,29 @@ static int cli_io_handler_dump_resolvers_to_buffer(struct appctx *appctx) chunk_appendf(&trash, " too_big: %lld\n", ns->counters->app.resolver.too_big); chunk_appendf(&trash, " truncated: %lld\n", ns->counters->app.resolver.truncated); chunk_appendf(&trash, " outdated: %lld\n", ns->counters->app.resolver.outdated); + if (ci_putchk(cs_ic(cs), &trash) == -1) + goto full; + appctx->ctx.cli.p2 = ns; } - chunk_appendf(&trash, "\n"); + + appctx->ctx.cli.p2 = NULL; + + /* was this the only section to dump ? */ + if (appctx->ctx.cli.p0) + break; } } - /* display response */ - if (ci_putchk(cs_ic(cs), &trash) == -1) { - /* let's try again later from this session. We add ourselves into - * this session's users so that it can remove us upon termination. - */ - cs_rx_room_blk(cs); - return 0; - } /* fall through */ default: appctx->st2 = STAT_ST_FIN; return 1; } + full: + /* the output buffer is full, retry later */ + cs_rx_room_blk(cs); + return 0; } /* register cli keywords */