ftp.nice.ch/pub/next/unix/network/system/gated.2.1pl2.NI.bs.tar.gz#/gated-2.1/src/main.c

This is main.c in view mode; [Download] [Up]

/*
 *  $Header: /disk/d/src/devel/gated/dist/src/RCS/main.c,v 2.1 92/02/24 14:12:46 jch Exp $
 */

/*%Copyright%*/
/************************************************************************
*									*
*	GateD, Release 2						*
*									*
*	Copyright (c) 1990,1991,1992 by Cornell University		*
*	    All rights reserved.					*
*									*
*	THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY		*
*	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT		*
*	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY		*
*	AND FITNESS FOR A PARTICULAR PURPOSE.				*
*									*
*	Royalty-free licenses to redistribute GateD Release		*
*	2 in whole or in part may be obtained by writing to:		*
*									*
*	    GateDaemon Project						*
*	    Information Technologies/Network Resources			*
*	    143 Caldwell Hall						*
*	    Cornell University						*
*	    Ithaca, NY 14853-2602					*
*									*
*	GateD is based on Kirton's EGP, UC Berkeley's routing		*
*	daemon	 (routed), and DCN's HELLO routing Protocol.		*
*	Development of Release 2 has been supported by the		*
*	National Science Foundation.					*
*									*
*	Please forward bug fixes, enhancements and questions to the	*
*	gated mailing list: gated-people@gated.cornell.edu.		*
*									*
*	Authors:							*
*									*
*		Jeffrey C Honig <jch@gated.cornell.edu>			*
*		Scott W Brim <swb@gated.cornell.edu>			*
*									*
*************************************************************************
*									*
*      Portions of this software may fall under the following		*
*      copyrights:							*
*									*
*	Copyright (c) 1988 Regents of the University of California.	*
*	All rights reserved.						*
*									*
*	Redistribution and use in source and binary forms are		*
*	permitted provided that the above copyright notice and		*
*	this paragraph are duplicated in all such forms and that	*
*	any documentation, advertising materials, and other		*
*	materials related to such distribution and use			*
*	acknowledge that the software was developed by the		*
*	University of California, Berkeley.  The name of the		*
*	University may not be used to endorse or promote		*
*	products derived from this software without specific		*
*	prior written permission.  THIS SOFTWARE IS PROVIDED		*
*	``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,	*
*	INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF	*
*	MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.		*
*									*
************************************************************************/


/* main.c
 *
 * Main function of the EGP user process. Includes packet reception,
 * ICMP handler and timer interrupt handler.
 *
 * Functions: main, receive_packet, icmpin, timeout, getod, quit
 */
/*
 * Software Overview:
 *
 * At start up, the controlling function, main(), first sets tracing options
 * based on starting command arguments. It then calls the initialization
 * functions described in the next section, sets up signal handlers for
 * termination (SIGTERM) and timer interrupt (SIGALRM) signals, calls
 * task_dispatch() to start periodic interrupt processing, and finally waits in a
 * loop to receive incoming EGP or ICMP redirect packets
 *
 * When an EGP packet is received, egpin() is called to handle it. It in turn
 * calls a separate function for each EGP command type, which sends the
 * appropriate response. When an ICMP packet is received icmpin() is called.
 *
 * The timer interrupt routine, task_dispatch(), calls egpjob() to perform periodic
 * EGP processing such as reachability determination, command sending and
 * retransmission. It in turn calls separate functions to format each command
 * type. task_dispatch() also periodically calls rt_time() to increment route ages
 * and delete routes when too old.
 */

#include "include.h"
#include "bgp.h"
#include "egp.h"
#include "hello.h"
#include "icmp.h"
#include "rip.h"
#include "parse.h"
#if	defined(_IBMR2)
#include <time.h>
#endif				/* defined(_IBMR2) */
#include <sys/time.h>
#ifdef	SYSV
#include <sys/fcntl.h>
#endif	/* SYSV */
#include <sys/file.h>
#ifdef	SYSV
#include <sys/sioctl.h>
#include <sys/stropts.h>
#else	/* SYSV */
#include <sys/ioctl.h>
#endif	/* SYSV */

static int conf_file_specified;		/* A config file was specified */
static int no_config_file;		/* No config file present */

extern void trace_mark();

#ifdef	AGENT_SNMP
extern void snmp_init();

#endif				/* AGENT_SNMP */

#ifndef	vax11c
int
parse_args(argc, argv)
int argc;
char **argv;
{
    int arg_n, err_flag = 0;
    char *arg, *cp, *ap;
    char seen[MAXHOSTNAMELENGTH];

    trace_file = (char *) 0;
    memset(seen, (char) 0, MAXHOSTNAMELENGTH);

    for (arg_n = 1; arg_n < argc; arg_n++) {
	arg = argv[arg_n];
	if (*arg == '-') {
	    cp = arg + 1;
	    if (index(seen, *cp)) {
		(void) fprintf(stderr, "%s: duplicate switch: %s\n", my_name, arg);
		err_flag++;
		continue;
	    }
	    seen[strlen(seen)] = *cp;
	    switch (*cp++) {
		case 'c':
		    /* Test configuration */
		    test_flag++;
		    trace_flags_save = trace_flags = TR_GEN | TR_KRT | TR_CONFIG | TR_NOSTAMP;
		    break;
		case 'n':
		    /* Don't install in kernel */
		    install = FALSE;
		    break;
		case 't':
		    /* Set trace flags */
		    if (!(trace_flags_save = trace_args(cp))) {
			err_flag++;
		    }
		    break;
		case 'f':
		    /* Specify config file */
		    ap = arg + 2;
		    if (*ap == (char) 0) {
			if (((arg_n + 1) < argc) && (*argv[arg_n + 1] != '-')) {
			    ap = argv[++arg_n];
			}
		    }
		    if (*ap == (char) 0) {
			(void) fprintf(stderr, "%s: missing argument for switch: %s\n", my_name, arg);
			err_flag++;
			break;
		    }
		    EGPINITFILE = ap;
		    conf_file_specified = TRUE;
		    break;
		default:
		    (void) fprintf(stderr, "%s: invalid switch: %s\n", my_name, arg);
		    err_flag++;
	    }
	} else if (!trace_file) {
	    trace_file = arg;
	} else {
	    (void) fprintf(stderr, "%s: extraneous information on command line: %s\n", my_name, arg);
	    err_flag++;
	}
    }
    if (err_flag) {
	(void) fprintf(stderr, "Usage: %s [-c] [-n] [-t[flags]] [-f config-file] [trace-file]\n", my_name);
    }
    return (err_flag);
}

#else				/* vax11c */
int
 parse_args(argc, argv);
int argc;
char **argv;

{
    int i;

    for (i = 1; i < argc; i++) {
	if (strcasecmp(argv[i], "bootfile") == 0) {
	    if (i >= argc) {
		(void) printf("ERROR: No GATED boot file specified!\n");
		return (1);
	    }
	    i++;
	    EGPINITFILE = argv[i];
	    continue;
	}
	if (strcasecmp(argv[i], "trace") == 0) {
	    trace_flags = TR_INT | TR_EXT | TR_RT | TR_EGP;
	    continue;
	}
	if (strcasecmp(argv[i], "trace-all") == 0) {
	    trace_flags = TR_INT | TR_EXT | TR_RT | TR_EGP |
		TR_UPDATE | TR_RIP | TR_HELLO;
	    continue;
	}
	if (strcasecmp(argv[i], "trace-internal-errors") == 0) {
	    trace_flags |= TR_INT;
	    continue;
	}
	if (strcasecmp(argv[i], "trace-external-changes") == 0) {
	    trace_flags |= TR_EXT;
	    continue;
	}
	if (strcasecmp(argv[i], "trace-routing-changes") == 0) {
	    trace_flags |= TR_RT;
	    continue;
	}
	if (strcasecmp(argv[i], "trace-packets") == 0) {
	    trace_flags |= TR_EGP;
	    continue;
	}
	if (strcasecmp(argv[i], "trace-egp-updates") == 0) {
	    trace_flags |= TR_UPDATE;
	    continue;
	}
	if (strcasecmp(argv[i], "trace-rip-updates") == 0) {
	    trace_flags |= TR_RIP;
	    continue;
	}
	if (strcasecmp(argv[i], "trace-hello-updates") == 0) {
	    trace_flags |= TR_HELLO;
	    continue;
	}
#if	defined(AGENT_SNMP)
	if (strcasecmp(argv[i], "trace-snmp") == 0) {
	    trace_flags |= TR_SNMP;
	    continue;
	}
#endif				/* defined(AGENT_SNMP) */
	(void) printf("GATED bad arg \"%s\"\n", argv[i]);
	return (1);
    }
    return (0);
}

#endif				/* vax11c */

#ifndef vax11c
int
main(argc, argv)
#else				/* vax11c */
gw_main(argc, argv)
#endif				/* vax11c */
int argc;
char *argv[];
{
#ifdef vax11c
    int i;

#endif				/* vax11c */
    char *cp;
    FILE *fp;

    getod();				/* start time */

    if (!(my_hostname = (char *) calloc(MAXHOSTNAMELENGTH + 1, sizeof(char)))) {
	trace(TR_ALL, LOG_ERR, "main: calloc: %m");
	quit(errno);
    }
    if (gethostname(my_hostname, MAXHOSTNAMELENGTH + 1)) {
	trace(TR_ALL, LOG_ERR, "main: gethostname: %m");
	quit(errno);
    }
    /* check arguments for turning on tracing and a trace file */

    my_name = argv[0];
    if (cp = (char *) rindex(my_name, '/')) {
	my_name = cp + 1;
    }
    trace_flags = trace_flags_save = 0;
    if (parse_args(argc, argv)) {
	quit(0);
    }

    task_getpaths();

#ifndef vax11c
    if (!test_flag) {
	if (getuid()) {
	    fprintf(stderr, "%s: must be root\n",
		    my_name);
	    exit(2);
	}
	
	if (!trace_flags_save || trace_file) {
	    /* This code rearranged after reading "Unix Network Programming" */
	    /* by W. Richard Stevens */
	    int t;

	    /*
	     * On System V if we were started by init from /etc/inittab there
	     * is no need to detach.
	     * There is some ambiguity here if we were orphaned by another
	     * process.
	     */
	    if (getppid() != 1) {
		/* Ignore terminal signals */
#ifdef	SIGTTOU
		signal(SIGTTOU, SIG_IGN);
#endif	/* SIGTTOU */
#ifdef	SIGTTIN
		signal(SIGTTIN, SIG_IGN);
#endif	/* SIGTTIN */
#ifdef	SIGTSTP
		signal(SIGTSTP, SIG_IGN);
#endif	/* SIGTSTP */
#ifdef	sigmask
		/* Prevent any SIGCHLDs until we are ready for them. */
		/* Note that this will hopefully prevent the SIGCHLD */
		/* signals we get when we have not fork()ed any children */
		sigblock(sigmask(SIGCHLD));
#endif	/* sigmask */

		switch (fork()) {
		case 0:
		    /* Child */
		    break;

		case -1:
		    /* Error */
		    perror("main: fork");
		    exit(1);

		default:
		    /* Parent */
		    exit(0);
		}

		/* Remove our association with a controling tty */
#ifdef	USE_SETPGRP
		t = setpgrp();
		if (t < 0) {
		    perror("main: setpgrp");
		    exit(1);
		}

		signal(SIGHUP, SIG_IGN);

		/* Fork again so we are not a process group leader */
		switch (fork()) {
		case 0:
		    /* Child */
		    break;

		case -1:
		    /* Error */
		    perror("main: fork");
		    exit(1);

		default:
		    /* Parent */
		    exit(0);
		}
#else	/* USE_SETPGRP */
		t = setpgrp(0, getpid());
		if (t < 0) {
		    perror("main: setpgrp");
		    exit(1);
		}


		t = open("/dev/tty", O_RDWR, 0);
		if (t >= 0) {
		    if (ioctl(t, TIOCNOTTY, (char *) 0) < 0) {
			perror("main: ioctl(TIOCNOTTY)");
			exit(1);
		    }
		    (void) close(t);
		}
#endif	/* USE_SETPGRP */
	    }

	    /* Close all open files */
	    t = getdtablesize();
	    do {
		(void) close(--t);
	    } while (t);

	    /* Reset umask */
	    umask(0);

	}
    }
    my_pid = my_mpid = getpid();

#if	defined(LOG_DAEMON)
    openlog(my_name, LOG_PID | LOG_CONS | LOG_NDELAY, LOG_FACILITY);
    (void) setlogmask(LOG_UPTO(LOG_NOTICE));
#else				/* defined(LOG_DAEMON) */
    openlog(my_name, LOG_PID);
#endif				/* defined(LOG_DAEMON) */

    if (trace_flags_save) {
	(void) trace_on(trace_file, TRUE);
    }
#endif				/* vax11c */

    trace(TR_ALL, 0, NULL);
    trace(TR_ALL, LOG_NOTICE, "Start %s[%d] version %s built %s", my_name, my_pid, version, build_date);
    trace(TR_ALL, 0, NULL);

/* open initialization file */
    no_config_file = FALSE;

    rt_init();				/* initialize route hash tables */

    control_init();			/* initialize control info tables */

    if_init();				/* initialize interface tables */

    krt_init();				/* Read kernel routing table */

    /*
     * initialize the hello_default net.
     */
    sockclear_in(&default_net);
    default_net.sin_addr.s_addr = htonl((u_long) DEFAULTNET);

    trace(TR_TASK, 0, NULL);
    trace(TR_TASK, 0, "main: Initializing protocols and tasks:");

    if (parse_parse(EGPINITFILE)) {	/* Read the config file */
	quit(0);
    }
#if	defined(PROTO_ICMP) && !defined(RTM_ADD)
    icmp_init();			/* Initialize to catch ICMP redirects */
#endif				/* defined(PROTO_ICMP) && !defined(RTM_ADD) */
#ifdef	PROTO_EGP
    egp_init();
#endif				/* PROTO_EGP */
#ifdef	PROTO_BGP
    bgp_init();
#endif				/* PROTO_BGP */
#ifdef	PROTO_RIP
    rip_init();
#endif				/* PROTO_RIP */
#ifdef	PROTO_HELLO
    hello_init();
#endif				/* PROTO_HELLO */
#ifdef	AGENT_SNMP
    snmp_init();
#endif				/* AGENT_SNMP */

    (void) timer_create((task *) 0,
			0,
			"Time.Mark",
			0,
			(time_t) TIME_MARK,
			trace_mark);

    trace(TR_TASK, 0, NULL);

    if_rtinit();			/* initialize interior routes for direct nets */

    if (no_config_file
#ifdef	PROTO_RIP
	&& !rip_supplier
#endif				/* PROTO_RIP */
	&& rt_locate(RTS_NETROUTE, (sockaddr_un *) & default_net, RTPROTO_KERNEL)) {
	trace(TR_ALL, 0, NULL);
	trace(TR_ALL, LOG_NOTICE, "No config file, one interface and a default route, gated exiting");
	trace(TR_ALL, 0, NULL);
	quit(0);
    }
    trace(TR_ALL, 0, NULL);
    trace(TR_ALL, 0, "***Routes are %sbeing installed in kernel", install ? "" : "not ");
    trace(TR_ALL, 0, NULL);

    if (test_flag) {
	/* Just testing configuration */
	trace_dump(TRUE);
	quit(0);
    }
#ifndef vax11c
    fp = fopen(PIDFILE, "w");
    if (fp != NULL) {
	(void) fprintf(fp, "%d\n", my_pid);
	(void) fclose(fp);
    }
    fp = fopen(VERSIONFILE, "w");
    if (fp != NULL) {
	(void) fprintf(fp, "%s version %s built %s\n\tpid %d, started %s",
		       my_name, version, build_date, my_pid, time_full);
	(void) fclose(fp);
    }
    task_init();
#endif				/* vax11c */

    getod();
    srandom((unsigned) time_sec);

    trace(TR_INT, 0, NULL);
    trace(TR_INT, LOG_NOTICE, "Commence routing updates");
    trace(TR_INT, 0, NULL);

    task_main();

    return (0);				/* To keep the complier happy */
}


/*
 * get time of day in seconds and as an ASCII string.
 * Called at each interrupt and saved in external variables.
 */

void
getod()
{
    struct timeval tp;
    struct timezone tzp;
    struct tm *tm;

    if (gettimeofday(&tp, &tzp)) {
	trace(TR_ALL, LOG_ERR, "getod: gettimeofday: %m");
    }
    time_sec = tp.tv_sec;
    tm = localtime(&tp.tv_sec);
    (void) sprintf(time_string, "%d/%d %02d:%02d:%02d\n",
		   tm->tm_mon + 1, tm->tm_mday,
		   tm->tm_hour, tm->tm_min, tm->tm_sec);
    (void) strcpy(time_full, (char *) ctime(&tp.tv_sec));
}


/* exit gated */

void
quit(code)
int code;
{
    rt_default_reset();
    getod();
    trace(TR_ALL, 0, NULL);
    switch (code) {
	case 0:
	case EDESTADDRREQ:
	    tracef("Exit %s[%d] version %s", my_name, my_pid, version);
	    if (code) {
		errno = code;
		tracef(": %m");
	    }
	    trace(TR_ALL, LOG_NOTICE, NULL);
	    trace(TR_ALL, 0, NULL);
	    trace_close();
	    break;
	default:
	    errno = code;
	    trace(TR_ALL, LOG_NOTICE, "Abort %s[%d] version %s: %m", my_name, my_pid, version);
	    trace(TR_ALL, 0, NULL);
	    trace_close();
	    chdir(DUMPDIR);
	    abort();
	    break;
    };
    exit(code);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.