summaryrefslogtreecommitdiffstats
path: root/nest/cli.c
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>1999-12-06 13:34:45 +0100
committerMartin Mares <mj@ucw.cz>1999-12-06 13:34:45 +0100
commit34350a52700955d50895058d01b5407aea970e9b (patch)
tree925eac326696cfa553d92cc320dc88ea1280659b /nest/cli.c
parentf3792601dfe85c3017c984a6de5722d0e9da8a16 (diff)
downloadbird-34350a52700955d50895058d01b5407aea970e9b.tar
bird-34350a52700955d50895058d01b5407aea970e9b.zip
Implemented echoing of log messages to CLI connections. Just try `echo all'.
Diffstat (limited to 'nest/cli.c')
-rw-r--r--nest/cli.c169
1 files changed, 145 insertions, 24 deletions
diff --git a/nest/cli.c b/nest/cli.c
index addbd1e..c752cf7 100644
--- a/nest/cli.c
+++ b/nest/cli.c
@@ -15,6 +15,34 @@
pool *cli_pool;
+static byte *
+cli_alloc_out(cli *c, int size)
+{
+ struct cli_out *o;
+
+ if (!(o = c->tx_write) || o->wpos + size > o->end)
+ {
+ if (!o && c->tx_buf)
+ o = c->tx_buf;
+ else
+ {
+ o = mb_alloc(c->pool, sizeof(struct cli_out) + CLI_TX_BUF_SIZE);
+ if (c->tx_write)
+ c->tx_write->next = o;
+ else
+ c->tx_buf = o;
+ o->next = NULL;
+ o->wpos = o->outpos = o->buf;
+ o->end = o->buf + CLI_TX_BUF_SIZE;
+ }
+ c->tx_write = o;
+ if (!c->tx_pos)
+ c->tx_pos = o;
+ }
+ o->wpos += size;
+ return o->wpos - size;
+}
+
void
cli_printf(cli *c, int code, char *msg, ...)
{
@@ -22,7 +50,6 @@ cli_printf(cli *c, int code, char *msg, ...)
byte buf[1024];
int cd = code;
int size, cnt;
- struct cli_out *o;
va_start(args, msg);
if (cd < 0)
@@ -46,27 +73,44 @@ cli_printf(cli *c, int code, char *msg, ...)
}
size += cnt;
buf[size++] = '\n';
- if (!(o = c->tx_write) || o->wpos + size > o->end)
+ memcpy(cli_alloc_out(c, size), buf, size);
+}
+
+static void
+cli_copy_message(cli *c)
+{
+ byte *p, *q;
+ unsigned int cnt = 2;
+
+ if (c->ring_overflow)
{
- if (!o && c->tx_buf)
- o = c->tx_buf;
- else
- {
- o = mb_alloc(c->pool, sizeof(struct cli_out) + CLI_TX_BUF_SIZE);
- if (c->tx_write)
- c->tx_write->next = o;
- else
- c->tx_buf = o;
- o->next = NULL;
- o->wpos = o->outpos = o->buf;
- o->end = o->buf + CLI_TX_BUF_SIZE;
- }
- c->tx_write = o;
- if (!c->tx_pos)
- c->tx_pos = o;
+ byte buf[64];
+ int n = bsprintf(buf, "<%d messages lost>\n", c->ring_overflow);
+ c->ring_overflow = 0;
+ memcpy(cli_alloc_out(c, n), buf, n);
}
- memcpy(o->wpos, buf, size);
- o->wpos += size;
+ p = c->ring_read;
+ while (*p)
+ {
+ cnt++;
+ p++;
+ if (p == c->ring_end)
+ p = c->ring_buf;
+ ASSERT(p != c->ring_write);
+ }
+ c->async_msg_size += cnt;
+ q = cli_alloc_out(c, cnt);
+ *q++ = '+';
+ p = c->ring_read;
+ do
+ {
+ *q = *p++;
+ if (p == c->ring_end)
+ p = c->ring_buf;
+ }
+ while (*q++);
+ c->ring_read = p;
+ q[-1] = '\n';
}
static void
@@ -83,7 +127,7 @@ cli_free_out(cli *c)
if (o = c->tx_buf)
{
- c->tx_write = NULL;
+ c->tx_write = c->tx_pos = NULL;
o->wpos = o->outpos = o->buf;
while (p = o->next)
{
@@ -91,6 +135,7 @@ cli_free_out(cli *c)
mb_free(p);
}
}
+ c->async_msg_size = 0;
}
static byte *cli_rh_pos;
@@ -140,6 +185,10 @@ cli_event(void *data)
cli *c = data;
int err;
+ while (c->ring_read != c->ring_write &&
+ c->async_msg_size < CLI_MAX_ASYNC_QUEUE)
+ cli_copy_message(c);
+
if (c->tx_pos)
;
else if (c->cont)
@@ -168,16 +217,15 @@ cli_new(void *priv)
pool *p = rp_new(cli_pool, "CLI");
cli *c = mb_alloc(p, sizeof(cli));
+ bzero(c, sizeof(cli));
c->pool = p;
c->priv = priv;
c->event = ev_new(p);
c->event->hook = cli_event;
c->event->data = c;
- c->tx_buf = c->tx_pos = c->tx_write = NULL;
c->cont = cli_hello;
- c->cleanup = NULL;
- c->last_reply = 0;
c->parser_pool = lp_new(c->pool, 4096);
+ c->rx_buf = mb_alloc(c->pool, CLI_RX_BUF_SIZE);
ev_schedule(c->event);
return c;
}
@@ -196,9 +244,80 @@ cli_written(cli *c)
ev_schedule(c->event);
}
+static list cli_log_hooks;
+static int cli_log_inited;
+
+void
+cli_set_log_echo(cli *c, unsigned int mask, unsigned int size)
+{
+ if (c->ring_buf)
+ {
+ mb_free(c->ring_buf);
+ c->ring_buf = c->ring_end = c->ring_read = c->ring_write = NULL;
+ rem_node(&c->n);
+ }
+ c->log_mask = mask;
+ if (mask && size)
+ {
+ c->ring_buf = mb_alloc(c->pool, size);
+ c->ring_end = c->ring_buf + size;
+ c->ring_read = c->ring_write = c->ring_buf;
+ add_tail(&cli_log_hooks, &c->n);
+ c->log_threshold = size / 8;
+ }
+ c->ring_overflow = 0;
+}
+
+void
+cli_echo(unsigned int class, byte *msg)
+{
+ unsigned len, free, i, l;
+ cli *c;
+ byte *m;
+
+ if (!cli_log_inited || EMPTY_LIST(cli_log_hooks))
+ return;
+ len = strlen(msg) + 1;
+ WALK_LIST(c, cli_log_hooks)
+ {
+ if (!(c->log_mask & (1 << class)))
+ continue;
+ if (c->ring_read <= c->ring_write)
+ free = (c->ring_end - c->ring_buf) - (c->ring_write - c->ring_read + 1);
+ else
+ free = c->ring_read - c->ring_write - 1;
+ if (len > free ||
+ free < c->log_threshold && class < (unsigned) L_INFO[0])
+ {
+ c->ring_overflow++;
+ continue;
+ }
+ if (c->ring_read == c->ring_write)
+ ev_schedule(c->event);
+ m = msg;
+ l = len;
+ while (l)
+ {
+ if (c->ring_read <= c->ring_write)
+ i = c->ring_end - c->ring_write;
+ else
+ i = c->ring_read - c->ring_write;
+ if (i > l)
+ i = l;
+ memcpy(c->ring_write, m, i);
+ m += i;
+ l -= i;
+ c->ring_write += i;
+ if (c->ring_write == c->ring_end)
+ c->ring_write = c->ring_buf;
+ }
+ }
+}
+
void
cli_free(cli *c)
{
+ cli_set_log_echo(c, 0, 0);
if (c->cleanup)
c->cleanup(c);
rfree(c->pool);
@@ -208,4 +327,6 @@ void
cli_init(void)
{
cli_pool = rp_new(&root_pool, "CLI");
+ init_list(&cli_log_hooks);
+ cli_log_inited = 1;
}