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:
parent
beb5f78ada
commit
8691151dbd
@ -75,3 +75,4 @@ Reply codes of BIRD command-line interface
|
|||||||
9000 Command too long
|
9000 Command too long
|
||||||
9001 Parse error
|
9001 Parse error
|
||||||
9002 Invalid symbol type
|
9002 Invalid symbol type
|
||||||
|
9003 Pipelining not supported
|
||||||
|
21
nest/cli.c
21
nest/cli.c
@ -293,13 +293,20 @@ cli_event(void *data)
|
|||||||
c->cont(c);
|
c->cont(c);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = cli_get_command(c);
|
switch (cli_get_command(c))
|
||||||
if (!err)
|
{
|
||||||
return;
|
case CGC_OK:
|
||||||
if (err < 0)
|
cli_command(c);
|
||||||
cli_printf(c, 9000, "Command too long");
|
break;
|
||||||
else
|
case CGC_INCOMPLETE:
|
||||||
cli_command(c);
|
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);
|
cli_write_trigger(c);
|
||||||
|
11
nest/cli.h
11
nest/cli.h
@ -29,7 +29,7 @@ typedef struct cli {
|
|||||||
node n; /* Node in list of all log hooks */
|
node n; /* Node in list of all log hooks */
|
||||||
pool *pool;
|
pool *pool;
|
||||||
void *priv; /* Private to sysdep layer */
|
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;
|
struct cli_out *tx_buf, *tx_pos, *tx_write;
|
||||||
event *event;
|
event *event;
|
||||||
void (*cont)(struct cli *c);
|
void (*cont)(struct cli *c);
|
||||||
@ -81,6 +81,13 @@ static inline int cli_access_restricted(void)
|
|||||||
/* Functions provided by sysdep layer */
|
/* Functions provided by sysdep layer */
|
||||||
|
|
||||||
void cli_write_trigger(cli *);
|
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
|
#endif
|
||||||
|
@ -430,11 +430,11 @@ cli_tx(sock *s)
|
|||||||
cli_write(s->data);
|
cli_write(s->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
enum cli_get_command_result
|
||||||
cli_get_command(cli *c)
|
cli_get_command(cli *c)
|
||||||
{
|
{
|
||||||
sock *s = c->priv;
|
sock *s = c->priv;
|
||||||
byte *t = c->rx_aux ? : s->rbuf;
|
byte *t = s->rbuf;
|
||||||
byte *tend = s->rpos;
|
byte *tend = s->rpos;
|
||||||
byte *d = c->rx_pos;
|
byte *d = c->rx_pos;
|
||||||
byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
|
byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
|
||||||
@ -445,18 +445,21 @@ cli_get_command(cli *c)
|
|||||||
t++;
|
t++;
|
||||||
else if (*t == '\n')
|
else if (*t == '\n')
|
||||||
{
|
{
|
||||||
t++;
|
if (++t < tend)
|
||||||
|
return CGC_TRAILING;
|
||||||
|
|
||||||
|
s->rpos = s->rbuf;
|
||||||
c->rx_pos = c->rx_buf;
|
c->rx_pos = c->rx_buf;
|
||||||
c->rx_aux = t;
|
|
||||||
*d = 0;
|
*d = 0;
|
||||||
return (d < dend) ? 1 : -1;
|
return (d < dend) ? CGC_OK : CGC_TOO_LONG;
|
||||||
}
|
}
|
||||||
else if (d < dend)
|
else if (d < dend)
|
||||||
*d++ = *t++;
|
*d++ = *t++;
|
||||||
}
|
}
|
||||||
c->rx_aux = s->rpos = s->rbuf;
|
|
||||||
|
s->rpos = s->rbuf;
|
||||||
c->rx_pos = d;
|
c->rx_pos = d;
|
||||||
return 0;
|
return CGC_INCOMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
|
||||||
s->fast_rx = 1;
|
s->fast_rx = 1;
|
||||||
c->rx_pos = c->rx_buf;
|
c->rx_pos = c->rx_buf;
|
||||||
c->rx_aux = NULL;
|
|
||||||
rmove(s, c->pool);
|
rmove(s, c->pool);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -549,6 +549,6 @@ int sysdep_commit(struct config *new UNUSED, struct config *old UNUSED) { return
|
|||||||
void sysdep_shutdown_done(void) {}
|
void sysdep_shutdown_done(void) {}
|
||||||
|
|
||||||
#include "nest/cli.h"
|
#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) {}
|
void cli_write_trigger(cli *c UNUSED) {}
|
||||||
cli *cmd_reconfig_stored_cli;
|
cli *cmd_reconfig_stored_cli;
|
||||||
|
Loading…
Reference in New Issue
Block a user