freebsd-dev/usr.sbin/atm/scspd/scspd.c

547 lines
10 KiB
C

/*
*
* ===================================
* HARP | Host ATM Research Platform
* ===================================
*
*
* This Host ATM Research Platform ("HARP") file (the "Software") is
* made available by Network Computing Services, Inc. ("NetworkCS")
* "AS IS". NetworkCS does not provide maintenance, improvements or
* support of any kind.
*
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
* In no event shall NetworkCS be responsible for any damages, including
* but not limited to consequential damages, arising from or relating to
* any use of the Software or related support.
*
* Copyright 1994-1998 Network Computing Services, Inc.
*
* Copies of this Software may be made, however, the above copyright
* notice must be reproduced on all copies.
*
* @(#) $FreeBSD$
*
*/
/*
* Server Cache Synchronization Protocol (SCSP) Support
* ----------------------------------------------------
*
* SCSP server daemon main line code
*
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/ttycom.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netatm/queue.h>
#include <netatm/atm.h>
#include <netatm/atm_if.h>
#include <netatm/atm_sap.h>
#include <netatm/atm_sys.h>
#include <netatm/atm_ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <libatm.h>
#include <paths.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "scsp_msg.h"
#include "scsp_if.h"
#include "scsp_var.h"
#ifndef lint
__RCSID("@(#) $FreeBSD$");
#endif
/*
* Global variables
*/
char *prog;
char *scsp_config_file = SCSPD_CONFIG;
FILE *scsp_log_file = (FILE *)0;
int scsp_log_syslog = 0;
Scsp_server *scsp_server_head = (Scsp_server *)0;
Scsp_pending *scsp_pending_head = (Scsp_pending *)0;
int scsp_max_socket = -1;
int scsp_debug_mode = 0;
int scsp_trace_mode = 0;
/*
* Local variables
*/
static int scsp_hup_signal = 0;
static int scsp_int_signal = 0;
/*
* SIGHUP signal handler
*
* Arguments:
* sig signal number
*
* Returns:
* none
*
*/
void
scsp_sighup(sig)
int sig;
{
/*
* Flag the signal
*/
scsp_hup_signal = 1;
}
/*
* SIGINT signal handler
*
* Arguments:
* sig signal number
*
* Returns:
* none
*
*/
void
scsp_sigint(sig)
int sig;
{
/*
* Flag the signal
*/
scsp_int_signal = 1;
}
/*
* Process command line parameters
*
* Arguments:
* argc number of command-line arguments
* argv list of pointers to command-line arguments
*
* Returns:
* none
*
*/
void
initialize(argc, argv)
int argc;
char **argv;
{
int i;
char *cp;
/*
* Save program name, ignoring any path components
*/
if ((prog = (char *)strrchr(argv[0], '/')) != NULL)
prog++;
else
prog = argv[0];
/*
* Make sure we're being invoked by the super user
*/
i = getuid();
if (i != 0) {
fprintf(stderr, "%s: You must be root to run this program\n",
prog);
exit(1);
}
/*
* Check for command-line options
*/
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-d") == 0) {
/*
* -d option -- set debug mode
*/
scsp_debug_mode = 1;
} else if (strcmp(argv[i], "-f") == 0) {
/*
* -f option -- set config file name
*/
i++;
if (i >= argc) {
fprintf(stderr, "%s: Configuration file name missing\n",
prog);
exit(1);
}
scsp_config_file = argv[i];
} else if (strncmp(argv[i], "-T", 2) == 0) {
/*
* -T option -- trace options
*/
for (cp = &argv[i][2]; *cp; cp++) {
if (*cp == 'c')
scsp_trace_mode |= SCSP_TRACE_CAFSM;
else if (*cp == 'h')
scsp_trace_mode |= SCSP_TRACE_HFSM;
else if (*cp == 'i')
scsp_trace_mode |= SCSP_TRACE_CFSM;
else if (*cp == 'C')
scsp_trace_mode |= SCSP_TRACE_CA_MSG;
else if (*cp == 'H')
scsp_trace_mode |= SCSP_TRACE_HELLO_MSG;
else if (*cp == 'I')
scsp_trace_mode |= SCSP_TRACE_IF_MSG;
else
fprintf(stderr, "Invalid trace specification '%c' ignored\n",
*cp);
}
} else {
/*
* Error -- unrecognized option
*/
fprintf(stderr, "%s: Unrecognized option \"%s\"\n",
prog, argv[i]);
exit(1);
}
}
}
/*
* Daemon housekeeping
*
* Arguments:
* None
*
* Returns:
* None
*
*/
static void
start_daemon()
{
int dpid, fd, file_count, rc;
/*
* Ignore selected signals
*/
#ifdef SIGTTOU
signal(SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
signal(SIGTSTP, SIG_IGN);
#endif
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
/*
* Don't put the daemon into the background if
* we're in debug mode
*/
if (scsp_debug_mode)
goto daemon_bypass;
/*
* Put the daemon into the background
*/
dpid = fork();
if (dpid < 0) {
scsp_log(LOG_ERR, "fork failed");
abort();
}
if (dpid > 0) {
/*
* This is the parent process--just exit and let
* the daughter do all the work
*/
exit(0);
}
/*
* Disassociate from any controlling terminal
*/
rc = setpgrp(0, getpid());
if (rc <0) {
scsp_log(LOG_ERR, "can't change process group");
exit(1);
}
fd = open(_PATH_TTY, O_RDWR);
if (fd >= 0) {
ioctl(fd, TIOCNOTTY, (char *)0);
close(fd);
}
/*
* Close all open file descriptors
*/
file_count = getdtablesize();
for (fd=0; fd<file_count; fd++) {
close(fd);
}
/*
* Set up timers
*/
daemon_bypass:
init_timer();
/*
* Move to a safe directory
*/
chdir(SCSPD_DIR);
/*
* Clear the file mode creation mask
*/
umask(0);
/*
* Set up signal handlers
*/
if (signal(SIGHUP, scsp_sighup) == SIG_ERR) {
scsp_log(LOG_ERR, "SIGHUP signal setup failed");
exit(1);
}
if (signal(SIGINT, scsp_sigint) == SIG_ERR) {
scsp_log(LOG_ERR, "SIGINT signal setup failed");
exit(1);
}
/*
* Set up syslog for error logging
*/
if (scsp_log_syslog || !scsp_log_file) {
openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON);
}
scsp_log(LOG_INFO, "Starting SCSP daemon");
}
/*
* Main line code
*
* Process command line parameters, read configuration file, connect
* to configured clients, process data from DCSs.
*
* Arguments:
* argc number of command-line arguments
* argv list of pointers to command-line arguments
*
* Returns:
* none
*
*/
int
main(argc, argv)
int argc;
char *argv[];
{
int i, rc, scsp_server_lsock;
Scsp_server *ssp;
Scsp_dcs *dcsp;
Scsp_pending *next_psp, *psp;
fd_set read_set, write_set, except_set;
/*
* Process command line arguments
*/
initialize(argc, argv);
/*
* Put the daemon into the background
*/
start_daemon();
/*
* Process configuration file
*/
rc = scsp_config(scsp_config_file);
if (rc) {
scsp_log(LOG_ERR, "Found %d error%s in configuration file",
rc, ((rc == 1) ? "" : "s"));
exit(1);
}
/*
* Open the trace file if we need one
*/
if (scsp_trace_mode) {
scsp_open_trace();
}
/*
* Listen for connections from clients
*/
scsp_server_lsock = scsp_server_listen();
if (scsp_server_lsock == -1) {
scsp_log(LOG_ERR, "server listen failed");
abort();
}
/*
* Main program loop -- we wait for:
* a server listen to complete
* a DCS listen to complete
* a DCS connect to complete
* data from a server
* data from a DCS
*/
while (1) {
/*
* Set up the file descriptor sets and select to wait
* for input
*/
FD_ZERO(&read_set);
FD_ZERO(&write_set);
FD_ZERO(&except_set);
FD_SET(scsp_server_lsock, &read_set);
for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) {
if (ssp->ss_dcs_lsock != -1)
FD_SET(ssp->ss_dcs_lsock, &read_set);
if (ssp->ss_sock != -1)
FD_SET(ssp->ss_sock, &read_set);
for (dcsp = ssp->ss_dcs; dcsp;
dcsp = dcsp->sd_next) {
if (dcsp->sd_sock != -1) {
if (dcsp->sd_hello_state ==
SCSP_HFSM_DOWN )
FD_SET(dcsp->sd_sock,
&write_set);
else
FD_SET(dcsp->sd_sock,
&read_set);
}
}
}
for (psp = scsp_pending_head; psp; psp = psp->sp_next) {
FD_SET(psp->sp_sock, &read_set);
}
rc = select(scsp_max_socket + 1, &read_set,
&write_set, &except_set,
(struct timeval *)0);
if (rc < 0) {
/*
* Select error--check for possible signals
*/
if (harp_timer_exec) {
/*
* Timer tick--process it
*/
timer_proc();
continue;
} else if (scsp_hup_signal) {
/*
* SIGHUP signal--reconfigure
*/
scsp_hup_signal = 0;
scsp_reconfigure();
continue;
} else if (scsp_int_signal) {
/*
* SIGINT signal--dump control blocks
*/
print_scsp_dump();
scsp_int_signal = 0;
continue;
} else if (errno == EINTR) {
/*
* EINTR--just ignore it
*/
continue;
} else {
/*
* Other error--this is a problem
*/
scsp_log(LOG_ERR, "Select failed");
abort();
}
}
/*
* Check the read set for connections from servers
*/
if (FD_ISSET(scsp_server_lsock, &read_set)) {
FD_CLR(scsp_server_lsock, &read_set);
rc = scsp_server_accept(scsp_server_lsock);
}
/*
* Check the write set for new connections to DCSs
*/
for (i = 0; i <= scsp_max_socket; i++) {
if (FD_ISSET(i, &write_set)) {
FD_CLR(i, &write_set);
if ((dcsp = scsp_find_dcs(i)) != NULL) {
rc = scsp_hfsm(dcsp,
SCSP_HFSM_VC_ESTAB,
(Scsp_msg *)0);
}
}
}
/*
* Check the read set for connections from DCSs
*/
for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) {
if (ssp->ss_dcs_lsock != -1 &&
FD_ISSET(ssp->ss_dcs_lsock,
&read_set)) {
FD_CLR(ssp->ss_dcs_lsock, &read_set);
dcsp = scsp_dcs_accept(ssp);
if (dcsp) {
rc = scsp_hfsm(dcsp,
SCSP_HFSM_VC_ESTAB,
(Scsp_msg *)0);
}
}
}
/*
* Check the read set for data from pending servers
*/
for (psp = scsp_pending_head; psp; psp = next_psp) {
next_psp = psp->sp_next;
if (FD_ISSET(psp->sp_sock, &read_set)) {
FD_CLR(psp->sp_sock, &read_set);
rc = scsp_pending_read(psp);
}
}
/*
* Check the read set for data from servers or DCSs
*/
for (i = 0; i <= scsp_max_socket; i++) {
if (FD_ISSET(i, &read_set)) {
if ((ssp = scsp_find_server(i)) != NULL) {
rc = scsp_server_read(ssp);
} else if ((dcsp = scsp_find_dcs(i)) != NULL) {
rc = scsp_dcs_read(dcsp);
}
}
}
}
}