# /* icmpd.c */ /* EMACS_MODES: c !fill */ #include #include #include "params.h" #include "request.h" #include "timer.h" #include "extern.h" /* This is the main routine for the icmp/ggp server process. Create a * lock file containing our process id, open up the request file directory * and the network connection, and then wait for something to wake us up. * If awakened by an arriving network packet, process it; if awakened * by a user request, process it. Also handle any timeouts that might * occur. * * Calling sequence: * icmpd [log] * The log parameter, if present, is bit-coded to give the logging level * to be supported: * bit 0 - log all icmp and ggp errors * bit 1 - log all locally originated icmp and ggp transactions * bit 2 - log all foreign originated icmp and ggp transactions * bit 3 - log all transmitted packets * bit 4 - log all received packets * All logging is to the standard output. If no logging parameter is * present, no logging is done. * In addition, logging may be turned on and off dynamically by sending * the daemon certain signals (eg. by using the kill(1) command). The * signals 20 + (bit number) toggle the state of the logging level * bits as defined above. */ main (argc, argv) int argc; reg char **argv; { reg FILE *dirfile; /* request file directory ptr */ reg int sleeptime; /* time to sleep now */ setbuf (stdout, NULL); /* NO BUFFER ON LOG FILE! */ log = 0; if (argc > 1 && (sscanf (argv[1], "%o", &log) <= 0)) { printf ("usage: %s [log level]\n", argv[0]); exit (1); } creat_lock (); init_sigs (); time (&curtime); /* get time and insure all signals */ /* have been received */ logdate (); printf ("icmp daemon started\n"); if ((dirfile = fopen (DIRNAME, "r")) < 0) { printf ("unable to open directory, error = %d\n", errno); clean_exit (0); } if (icmp_init () < 0) { printf ("unable to open icmp conn., error = %d\n", errno); clean_exit (0); } if (ggp_init () < 0 ) { printf ("unable to open ggp conn., error = %d\n", errno); clean_exit (0); } sleeptime = 0; for (;;) { /* main loop */ if (!tst_and_clr(&work_avail)) { if (sleeptime != 0) sleep (sleeptime); else pause (); } time (&curtime); if (tst_and_clr (&net_avail)) { do_icmp (); do_ggp (); } if (tst_and_clr (&req_avail)) do_req (dirfile); sleeptime = do_timeouts (); } } creat_lock () /* Create a lock file in the icmp daemon's directory, containing our * process id. If such a lock file already exists, we are a duplicate * and should die immediately, so do so. */ { reg int lkfd; /* lock file descriptor */ reg int pid; /* my pid */ char cpid[10]; /* my pid in characters */ chdir (DIRNAME); /* change to our directory */ pid = getpid (); /* get our pid */ if ((lkfd = creat (LOCKNAME, 0444)) < 0) { /* daemon already exists */ printf ("duplicate daemon %d exiting\n", pid); exit (1); } sprintf (cpid, "%d\n", pid); write (lkfd, cpid, strlen (cpid)); close (lkfd); } init_sigs () /* Set up signal handlers for all signals handled by the daemon. */ { reg int i; /* loop counter */ signal (SIGHUP, clean_exit); signal (SIGINT, SIG_IGN); signal (SIGALRM, timer); signal (SIGTERM, clean_exit); signal (SIGCTLA, req_int); signal (SIGAIO, netio); for (i = 0; i <= MAX_LOG; i++) signal (SIGLOG + i, logint); } clean_exit (signo) /* This routine is called to clean up after the daemon and exit, when * the daemon is signalled with a hangup or software kill signal. * It removes the daemon's lock file, and exits, relying on the system * to close all open files. * * Arguments: */ int signo; /* signal number */ { logdate (); printf ("exiting with signal %d\n", signo); unlink (LOCKNAME); exit (0); } timer (signo) /* This routine is called on receipt of an alarm signal. It simply * reenables receipt of that signal, sets the work available flag, * and returns. The main routine will have been awakened by the * receipt of the signal and will process the timeouts. * * Arguments: */ int signo; /* the signal number */ { signal (signo, timer); work_avail = 1; } req_int (signo) /* This routine is called on receipt of a special interrupt signal. The * special interrupt signal is sent by the user request programs to * indicate that a user request is pending. This routine sets the * request pending and work available flags and returns; the main * process will have been awakened by the occurrence of the signal * to process the request. * * Arguments: */ int signo; /* signal number */ { signal (signo, req_int); req_avail = 1; work_avail = 1; } netio (signo) /* This routine is called on receipt of a network interrupt signal. The * network interrupt signal is sent by the kernel to indicate that network * input or output has completed. This routine sets the network work * pending and work available flags and returns; the main * process will have been awakened by the occurrence of the signal * to process the request. * * Arguments: */ int signo; /* signal number */ { signal (signo, netio); net_avail = 1; work_avail = 1; } logint (signo) /* This routine is called on receipt of one of signals 20 through * 24, which are used to change the logging level of the daemon. * Each signal corresponds to one bit of the logging level word; * receiving a signal causes the corresponding bit to be complemented. * This routine just complements the appropriate bit. * * Arguments: */ int signo; /* signal no. (= bit no. + 20) */ { reg int bit; reg int mask; signal (signo, logint); bit = signo - SIGLOG; mask = 1 << bit; if (log & mask) log &= ~mask; else log |= mask; } logdate () /* Print the current date and time into the log */ { printf ("\n%s", ctime (&curtime)); }