diff --git a/nest/Makefile b/nest/Makefile index d7689e0f..5b6b414e 100644 --- a/nest/Makefile +++ b/nest/Makefile @@ -1,4 +1,4 @@ -source=rt-table.c rt-fib.c rt-attr.c proto.c iface.c rt-dev.c password.c +source=rt-table.c rt-fib.c rt-attr.c proto.c iface.c rt-dev.c password.c cli.c root-rel=../ dir-name=nest diff --git a/nest/cli.c b/nest/cli.c new file mode 100644 index 00000000..09ebe96b --- /dev/null +++ b/nest/cli.c @@ -0,0 +1,144 @@ +/* + * BIRD Internet Routing Daemon -- Command-Line Interface + * + * (c) 1999 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include "nest/bird.h" +#include "lib/string.h" +#include "nest/cli.h" + +pool *cli_pool; + +void +cli_printf(cli *c, int code, char *msg, ...) +{ + va_list args; + byte buf[1024]; + int flag = (code < 0) ? '-' : ' '; + int size; + struct cli_out *o; + + va_start(args, msg); + if (code < 0) + code = -code; + bsprintf(buf, "%04d%c", code, flag); + size = bvsnprintf(buf+5, sizeof(buf)-6, msg, args); + if (size < 0) + size = bsprintf(buf, "9999%c", flag); + else + size += 5; + buf[size++] = '\n'; + if (!(o = c->tx_write) || o->wpos + size > o->end) + { + 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; + } + memcpy(o->wpos, buf, size); + o->wpos += size; +} + +static void +cli_free_out(cli *c) +{ + struct cli_out *o, *p; + + if (o = c->tx_buf) + { + c->tx_write = o; + o->wpos = o->outpos = o->buf; + while (p = o->next) + { + o->next = p->next; + mb_free(p); + } + } +} + +static int +cli_flush(cli *c) +{ + if (cli_write(c)) + { + cli_free_out(c); + return 1; + } + return 0; +} + +static int +cli_event(void *data) +{ + cli *c = data; + int err; + + debug("CLI EVENT\n"); + if (!c->inited) + { + c->inited = 1; + cli_printf(c, 0, "Welcome!"); + cli_printf(c, 0, "Here"); + return cli_flush(c); + } + err = cli_get_command(c); + if (!err) + return 0; + if (err < 0) + debug("CLI CMD ERR\n"); + else + debug("CLI CMD %s\n", c->rx_buf); + return 1; +} + +cli * +cli_new(void *priv) +{ + pool *p = rp_new(cli_pool, "CLI"); + cli *c = mb_alloc(p, 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->inited = 0; + cli_kick(c); + return c; +} + +void +cli_kick(cli *c) +{ + debug("CLI KICK\n"); + ev_schedule(c->event); +} + +void +cli_written(cli *c) +{ + debug("CLI WRITTEN\n"); + cli_free_out(c); + cli_kick(c); +} + +void +cli_free(cli *c) +{ + rfree(c->pool); +} + +void +cli_init(void) +{ + cli_pool = rp_new(&root_pool, "CLI"); +} diff --git a/nest/cli.h b/nest/cli.h new file mode 100644 index 00000000..69271fec --- /dev/null +++ b/nest/cli.h @@ -0,0 +1,49 @@ +/* + * BIRD Internet Routing Daemon -- Command-Line Interface + * + * (c) 1999 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_CLI_H_ +#define _BIRD_CLI_H_ + +#include "lib/resource.h" +#include "lib/event.h" + +#define CLI_RX_BUF_SIZE 4096 +#define CLI_TX_BUF_SIZE 4096 + +struct cli_out { + struct cli_out *next; + byte *wpos, *outpos, *end; + byte buf[0]; +}; + +typedef struct cli { + pool *pool; + void *priv; /* Private to sysdep layer */ + int inited; + byte rx_buf[CLI_RX_BUF_SIZE]; + byte *rx_pos, *rx_aux; /* sysdep */ + struct cli_out *tx_buf, *tx_pos, *tx_write; + event *event; +} cli; + +extern pool *cli_pool; + +cli *cli_new(void *); +void cli_init(void); +void cli_free(cli *); +void cli_kick(cli *); +void cli_written(cli *); +void cli_printf(cli *, int, char *, ...); + +/* Function provided by sysdep layer */ + +int cli_write(cli *); +void cli_disconnect(cli *); +int cli_get_command(cli *); + +#endif diff --git a/sysdep/unix/client-main.c b/sysdep/unix/client-main.c index da01e21b..01a79864 100644 --- a/sysdep/unix/client-main.c +++ b/sysdep/unix/client-main.c @@ -12,6 +12,7 @@ #include #include "nest/bird.h" +#include "lib/resource.h" /* For dmalloc */ #include "client/client.h" #include "unix.h" diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index ed89ef1b..f717fb0c 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -21,6 +21,7 @@ #include "nest/route.h" #include "nest/protocol.h" #include "nest/iface.h" +#include "nest/cli.h" #include "conf/conf.h" #include "filter/filter.h" @@ -86,6 +87,119 @@ async_config(void) debug("Asynchronous reconfigurations are not supported in demo version\n"); } +/* + * Command-Line Interface + */ + +static sock *cli_sk; + +void +cli_disconnect(cli *c) +{ + bug("CLI DISCONNECT: Not implemented"); /* FIXME */ +} + +int +cli_write(cli *c) +{ + sock *s = c->priv; + + if (c->tx_pos) + { + struct cli_out *o = c->tx_pos; + c->tx_pos = o->next; + s->tbuf = o->outpos; + return sk_send(s, o->wpos - o->outpos); + } + return 1; +} + +int +cli_get_command(cli *c) +{ + sock *s = c->priv; + byte *t = c->rx_aux ? : s->rbuf; + byte *tend = s->rpos; + byte *d = c->rx_pos; + byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2; + + while (t < tend) + { + if (*t == '\r') + t++; + else if (*t == '\n') + { + t++; + c->rx_pos = c->rx_buf; + c->rx_aux = t; + *d = 0; + return (d < dend) ? 1 : -1; + } + else if (d < dend) + *d++ = *t++; + } + c->rx_aux = s->rpos = s->rbuf; + c->rx_pos = d; + return 0; +} + +static int +cli_rx(sock *s, int size) +{ + debug("CLI RX\n"); + cli_kick(s->data); + return 0; +} + +static void +cli_tx(sock *s) +{ + cli *c = s->data; + + debug("CLI TX\n"); + if (cli_write(c)) + cli_written(c); +} + +static void +cli_err(sock *s, int err) +{ + if (err) + log(L_INFO "CLI connection dropped: %s", strerror(err)); + else + log(L_INFO "CLI connection closed"); + s->type = SK_DELETED; + cli_free(s->data); +} + +static int +cli_connect(sock *s, int size) +{ + cli *c; + + log(L_INFO "CLI connect"); + s->rx_hook = cli_rx; + s->tx_hook = cli_tx; + s->err_hook = cli_err; + s->rbsize = 1024; + s->data = c = cli_new(s); + c->rx_pos = c->rx_buf; + c->rx_aux = NULL; + return 1; +} + +static void +cli_init_unix(void) +{ + sock *s; + + cli_init(); + s = cli_sk = sk_new(cli_pool); + s->type = SK_UNIX_PASSIVE; + s->rx_hook = cli_connect; + sk_open_unix(s, PATH_CONTROL_SOCKET); +} + /* * Shutdown */ @@ -101,6 +215,7 @@ async_shutdown(void) void protos_shutdown_notify(void) { + unlink(PATH_CONTROL_SOCKET); die("System shutdown completed"); } @@ -194,7 +309,7 @@ main(int argc, char **argv) #endif log_init_debug(NULL); - setvbuf(stdout, NULL, _IONBF, 0); /* And yes, this does make a difference */ + setvbuf(stdout, NULL, _IONBF, 0); /* FIXME: Kill some day. */ setvbuf(stderr, NULL, _IONBF, 0); parse_args(argc, argv); @@ -214,6 +329,8 @@ main(int argc, char **argv) signal_init(); + cli_init_unix(); + protos_start(); ev_run_list(&global_event_list);