0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 12:18:42 +00:00

CLI fix for long-lived sessions during high loads

When there is a continuos stream of CLI commands, cli_get_command()
always returns 1 (there is a new command). Anyway, the socket receive
buffer was reset only when there was no command at all, leading to a
strange behavior: after a while, the CLI receive buffer came to its end,
then read() was called with zero size buffer, it returned 0 which was
interpreted as EOF.

Fixing this by:
* resetting the buffer any time CLI RX gets to EOL
* explicitly refusing to pipeline

In future, we may implement CLI pipelining, yet to make it conveniently,
a push-parser may come handy instead of the current implementation.
This commit is contained in:
Maria Matejka 2022-07-11 13:53:09 +02:00
parent beb5f78ada
commit 8691151dbd
5 changed files with 35 additions and 18 deletions

View File

@ -75,3 +75,4 @@ Reply codes of BIRD command-line interface
9000 Command too long
9001 Parse error
9002 Invalid symbol type
9003 Pipelining not supported

View File

@ -293,13 +293,20 @@ cli_event(void *data)
c->cont(c);
else
{
err = cli_get_command(c);
if (!err)
return;
if (err < 0)
cli_printf(c, 9000, "Command too long");
else
switch (cli_get_command(c))
{
case CGC_OK:
cli_command(c);
break;
case CGC_INCOMPLETE:
return;
case CGC_TOO_LONG:
cli_printf(c, 9000, "Command too long");
break;
case CGC_TRAILING:
cli_printf(c, 9003, "Pipelining not supported");
break;
}
}
cli_write_trigger(c);

View File

@ -29,7 +29,7 @@ typedef struct cli {
node n; /* Node in list of all log hooks */
pool *pool;
void *priv; /* Private to sysdep layer */
byte *rx_buf, *rx_pos, *rx_aux; /* sysdep */
byte *rx_buf, *rx_pos; /* sysdep */
struct cli_out *tx_buf, *tx_pos, *tx_write;
event *event;
void (*cont)(struct cli *c);
@ -81,6 +81,13 @@ static inline int cli_access_restricted(void)
/* Functions provided by sysdep layer */
void cli_write_trigger(cli *);
int cli_get_command(cli *);
enum cli_get_command_result {
CGC_OK,
CGC_INCOMPLETE,
CGC_TOO_LONG,
CGC_TRAILING,
};
enum cli_get_command_result cli_get_command(cli *);
#endif

View File

@ -430,11 +430,11 @@ cli_tx(sock *s)
cli_write(s->data);
}
int
enum cli_get_command_result
cli_get_command(cli *c)
{
sock *s = c->priv;
byte *t = c->rx_aux ? : s->rbuf;
byte *t = s->rbuf;
byte *tend = s->rpos;
byte *d = c->rx_pos;
byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
@ -445,18 +445,21 @@ cli_get_command(cli *c)
t++;
else if (*t == '\n')
{
t++;
if (++t < tend)
return CGC_TRAILING;
s->rpos = s->rbuf;
c->rx_pos = c->rx_buf;
c->rx_aux = t;
*d = 0;
return (d < dend) ? 1 : -1;
return (d < dend) ? CGC_OK : CGC_TOO_LONG;
}
else if (d < dend)
*d++ = *t++;
}
c->rx_aux = s->rpos = s->rbuf;
s->rpos = s->rbuf;
c->rx_pos = d;
return 0;
return CGC_INCOMPLETE;
}
static int
@ -493,7 +496,6 @@ cli_connect(sock *s, uint size UNUSED)
s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
s->fast_rx = 1;
c->rx_pos = c->rx_buf;
c->rx_aux = NULL;
rmove(s, c->pool);
return 1;
}

View File

@ -549,6 +549,6 @@ int sysdep_commit(struct config *new UNUSED, struct config *old UNUSED) { return
void sysdep_shutdown_done(void) {}
#include "nest/cli.h"
int cli_get_command(cli *c UNUSED) { return 0; }
enum cli_get_command_result cli_get_command(cli *c UNUSED) { return CGC_OK; }
void cli_write_trigger(cli *c UNUSED) {}
cli *cmd_reconfig_stored_cli;