summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2009-07-14 14:18:54 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2009-07-14 14:18:54 +0200
commit6baef17ecf1ed994cfc8038bc610e8b7ff88506a (patch)
tree60f9b74e148cf87cd014ffd6c3f885f7d6c2b185
parent70670bf317a612a1700ffbd0dbc8d92614e0caf2 (diff)
Fixes bug in CLI TX buffer management.
-rw-r--r--nest/cli.c36
-rw-r--r--nest/cli.h2
-rw-r--r--sysdep/unix/main.c47
3 files changed, 55 insertions, 30 deletions
diff --git a/nest/cli.c b/nest/cli.c
index bd487d87..ace97beb 100644
--- a/nest/cli.c
+++ b/nest/cli.c
@@ -47,6 +47,20 @@
* The @this_cli variable points to a &cli structure of the session being
* currently parsed, but it's of course available only in command handlers
* not entered using the @cont hook.
+ *
+ * TX buffer management works as follows: At cli.tx_buf there is a
+ * list of TX buffers (struct cli_out), cli.tx_write is the buffer
+ * currently used by the producer (cli_printf(), cli_alloc_out()) and
+ * cli.tx_pos is the buffer currently used by the consumer
+ * (cli_write(), in system dependent code). The producer uses
+ * cli_out.wpos ptr as the current write position and the consumer
+ * uses cli_out.outpos ptr as the current read position. When the
+ * producer produces something, it calls cli_write_trigger(). If there
+ * is not enough space in the current buffer, the producer allocates
+ * the new one. When the consumer processes everything in the buffer
+ * queue, it calls cli_written(), tha frees all buffers (except the
+ * first one) and schedules cli.event .
+ *
*/
#include "nest/bird.h"
@@ -196,6 +210,14 @@ cli_free_out(cli *c)
c->async_msg_size = 0;
}
+void
+cli_written(cli *c)
+{
+ cli_free_out(c);
+ ev_schedule(c->event);
+}
+
+
static byte *cli_rh_pos;
static unsigned int cli_rh_len;
static int cli_rh_trick_flag;
@@ -263,11 +285,8 @@ cli_event(void *data)
else
cli_command(c);
}
- if (cli_write(c))
- {
- cli_free_out(c);
- ev_schedule(c->event);
- }
+
+ cli_write_trigger(c);
}
cli *
@@ -296,13 +315,6 @@ cli_kick(cli *c)
ev_schedule(c->event);
}
-void
-cli_written(cli *c)
-{
- cli_free_out(c);
- ev_schedule(c->event);
-}
-
static list cli_log_hooks;
static int cli_log_inited;
diff --git a/nest/cli.h b/nest/cli.h
index 2e76db76..f816ef18 100644
--- a/nest/cli.h
+++ b/nest/cli.h
@@ -62,7 +62,7 @@ void cli_echo(unsigned int class, byte *msg);
/* Functions provided by sysdep layer */
-int cli_write(cli *);
+void cli_write_trigger(cli *);
int cli_get_command(cli *);
#endif
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index 5f5b165f..17845d20 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -178,22 +178,44 @@ cmd_reconfig(char *name, int type)
static sock *cli_sk;
static char *path_control_socket = PATH_CONTROL_SOCKET;
-int
+
+static void
cli_write(cli *c)
{
sock *s = c->priv;
- if (c->tx_pos)
+ while (c->tx_pos)
{
struct cli_out *o = c->tx_pos;
+
+ int len = o->wpos - o->outpos;
s->tbuf = o->outpos;
- if (sk_send(s, o->wpos - o->outpos) > 0)
- {
- c->tx_pos = o->next;
- ev_schedule(c->event);
- }
+ o->outpos = o->wpos;
+
+ if (sk_send(s, len) <= 0)
+ return;
+
+ c->tx_pos = o->next;
}
- return !c->tx_pos;
+
+ /* Everything is written */
+ s->tbuf = NULL;
+ cli_written(c);
+}
+
+void
+cli_write_trigger(cli *c)
+{
+ sock *s = c->priv;
+
+ if (s->tbuf == NULL)
+ cli_write(c);
+}
+
+static void
+cli_tx(sock *s)
+{
+ cli_write(s->data);
}
int
@@ -233,15 +255,6 @@ cli_rx(sock *s, int size UNUSED)
}
static void
-cli_tx(sock *s)
-{
- cli *c = s->data;
-
- if (cli_write(c))
- cli_written(c);
-}
-
-static void
cli_err(sock *s, int err)
{
if (config->cli_debug)