]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixes bug in CLI TX buffer management.
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 14 Jul 2009 12:18:54 +0000 (14:18 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 14 Jul 2009 12:18:54 +0000 (14:18 +0200)
nest/cli.c
nest/cli.h
sysdep/unix/main.c

index bd487d87319223e97b603c079c7e480597678d2b..ace97beb70a18ff87e09ed75e3b5c3f6b42979e3 100644 (file)
  * 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;
 
index 2e76db7650be737943216577e29777a8c34269c4..f816ef18afcdbef30a49d287ebcf02957aab238c 100644 (file)
@@ -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
index 5f5b165f3de330f7312b9ed3a69874180639d2db..17845d201cc89d25c29e6e5bf9baea0139ceb314 100644 (file)
@@ -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
@@ -232,15 +254,6 @@ cli_rx(sock *s, int size UNUSED)
   return 0;
 }
 
-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)
 {