bird/sysdep/unix/main.c
Martin Mares f545d38707 Added universal locking mechanism which will solve problems
with protocols wanting to use the same port on the same interface
during reconfiguration time.

How to use locks: In the if_notify hook, just order locks for the
interfaces you want to work with and do the real socket opening after the
lock hook function gets called. When you stop using the socket, close
it and rfree() the lock.

Please update your protocols to use the new locking mechanism.
1999-12-09 18:54:20 +00:00

363 lines
5.9 KiB
C

/*
* BIRD Internet Routing Daemon -- Unix Entry Point
*
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/signal.h>
#include "nest/bird.h"
#include "lib/lists.h"
#include "lib/resource.h"
#include "lib/socket.h"
#include "lib/event.h"
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/iface.h"
#include "nest/cli.h"
#include "nest/locks.h"
#include "conf/conf.h"
#include "filter/filter.h"
#include "unix.h"
#include "krt.h"
int shutting_down;
/*
* Debugging
*/
void
async_dump(void)
{
debug("INTERNAL STATE DUMP\n\n");
rdump(&root_pool);
sk_dump_all();
tm_dump_all();
if_dump_all();
neigh_dump_all();
rta_dump_all();
rt_dump_all();
protos_dump_all();
debug("\n");
}
/*
* Reading the Configuration
*/
static int conf_fd;
static char *config_name = PATH_CONFIG;
static int
cf_read(byte *dest, unsigned int len)
{
int l = read(conf_fd, dest, len);
if (l < 0)
cf_error("Read error");
return l;
}
void
sysdep_preconfig(struct config *c)
{
init_list(&c->logfiles);
}
void
sysdep_commit(struct config *c)
{
log_switch(&c->logfiles);
}
static void
read_config(void)
{
struct config *conf = config_alloc(config_name);
conf_fd = open(config_name, O_RDONLY);
if (conf_fd < 0)
die("Unable to open configuration file %s: %m", config_name);
cf_read_hook = cf_read;
if (!config_parse(conf))
die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
config_commit(conf);
}
void
async_config(void)
{
debug("Asynchronous reconfigurations are not supported in demo version\n");
}
/*
* Command-Line Interface
*/
static sock *cli_sk;
static char *path_control_socket = PATH_CONTROL_SOCKET;
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)
{
cli_kick(s->data);
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)
{
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);
s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
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;
if (sk_open_unix(s, path_control_socket) < 0)
die("Unable to create control socket %s", path_control_socket);
}
/*
* Shutdown
*/
void
async_shutdown(void)
{
debug("Shutting down...\n");
shutting_down = 1;
protos_shutdown();
}
void
protos_shutdown_notify(void)
{
unlink(PATH_CONTROL_SOCKET);
die("System shutdown completed");
}
/*
* Signals
*/
static void
handle_sighup(int sig)
{
debug("Caught SIGHUP...\n");
async_config_flag = 1;
}
static void
handle_sigusr(int sig)
{
debug("Caught SIGUSR...\n");
async_dump_flag = 1;
}
static void
handle_sigterm(int sig)
{
debug("Caught SIGTERM...\n");
async_shutdown_flag = 1;
}
static void
signal_init(void)
{
struct sigaction sa;
bzero(&sa, sizeof(sa));
sa.sa_handler = handle_sigusr;
sa.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &sa, NULL);
sa.sa_handler = handle_sighup;
sa.sa_flags = SA_RESTART;
sigaction(SIGHUP, &sa, NULL);
sa.sa_handler = handle_sigterm;
sa.sa_flags = SA_RESTART;
sigaction(SIGTERM, &sa, NULL);
signal(SIGPIPE, SIG_IGN);
}
/*
* Parsing of command-line arguments
*/
static char *opt_list = "c:dD:s:";
static int debug_flag = 1; /* FIXME: Turn off for production use */
static void
usage(void)
{
fprintf(stderr, "Usage: bird [-c <config-file>] [-d] [-D <debug-file>] [-s <control-socket>]\n");
exit(1);
}
static void
parse_args(int argc, char **argv)
{
int c;
while ((c = getopt(argc, argv, opt_list)) >= 0)
switch (c)
{
case 'c':
config_name = optarg;
break;
case 'd':
debug_flag |= 1;
break;
case 'D':
log_init_debug(optarg);
debug_flag |= 2;
break;
case 's':
path_control_socket = optarg;
break;
default:
usage();
}
if (optind < argc)
usage();
}
/*
* Hic Est main()
*/
int
main(int argc, char **argv)
{
#ifdef HAVE_LIBDMALLOC
if (!getenv("DMALLOC_OPTIONS"))
dmalloc_debug(0x2f03d00);
#endif
setvbuf(stdout, NULL, _IONBF, 0); /* FIXME: Kill some day. */
setvbuf(stderr, NULL, _IONBF, 0);
parse_args(argc, argv);
if (debug_flag == 1)
log_init_debug("");
log_init(debug_flag);
log(L_INFO "Launching BIRD " BIRD_VERSION "...");
debug("Initializing.\n");
resource_init();
olock_init();
io_init();
rt_init();
if_init();
protos_build();
add_tail(&protocol_list, &proto_unix_kernel.n);
add_tail(&protocol_list, &proto_unix_iface.n);
read_config();
signal_init();
cli_init_unix();
protos_start();
ev_run_list(&global_event_list);
async_dump();
debug("Entering I/O loop.\n");
io_loop();
bug("I/O loop died");
}