This is makecall.c in view mode; [Download] [Up]
/* ** Copyright (c) 1991 Bolt Beranek and Newman, Inc. ** All rights reserved. ** ** Redistribution and use in source and binary forms are permitted ** provided that: (1) source distributions retain this entire copyright ** notice and comment, and (2) distributions including binaries display ** the following acknowledgement: ``This product includes software ** developed by Bolt Beranek and Newman, Inc. and CREN/CSNET'' in the ** documentation or other materials provided with the distribution and in ** all advertising materials mentioning features or use of this software. ** Neither the name of Bolt Beranek and Newman nor CREN/CSNET may 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. */ #include <stdio.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> #include <netdb.h> #include <setjmp.h> #include <sgtty.h> #include <signal.h> #include <sys/types.h> #include <sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <net/if.h> #include <net/if_du.h> #include "diald.h" #include "dialupip.h" #ifdef sun #define GETDATAVAL(ifr) (*(int *)ifr.ifr_data) #define SETDATAVAL(ifr, i) (*(int *)(ifr).ifr_data = (i)) #else #define GETDATAVAL(ifr) ((int)ifr.ifr_data) #define SETDATAVAL(ifr, i) ((ifr).ifr_data = (caddr_t)(i)) #endif /* sun */ /* ** Local Variables */ static char device[12]; /* Device name */ static char tty[12]; /* Modem in use */ static int mypid; static int dialfout; /* Modem descriptor */ static long startipkts; /* Starting input packet count */ static long startopkts; /* Starting output packet count */ static struct ifreq ifr; static int oldinactive; /* Old inactivity value */ static struct sgttyb oldsgtty; /* Old TTY modes */ static jmp_buf opentimeout; /* Used for open timeouts */ static int sock; /* The global socket for use everywhere */ static time_t starttime; /* Time call started */ static time_t stoptime; /* Time call stopped */ static long duration; /* Duration of call in seconds */ static char sitename[30]; /* Name of site called */ extern char *strerror(); /* ** Log that a call failed. */ void failcall(devname, mesg) char *devname; char *mesg; { static char WHERE[] = "failcall"; int s; struct ifreq ifr; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't create socket for \"%s\", %m", devname); d_log(DLOG_GENERAL, WHERE, "%s", mesg); return; } (void)strcpy(ifr.ifr_name, devname); if (ioctl(s, SIOCFAILCALL, (caddr_t)&ifr) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't SIOCFAILCALL on \"%s\", %m", devname); d_log(DLOG_GENERAL, WHERE, "%s", mesg); return; } d_log(DLOG_ALL, WHERE, "Did SIOCFAILCALL on \"%s\"", devname); d_log(DLOG_ALL, WHERE, "%s", mesg); } /* ** Get the packet counts from the interface. */ static void getpacketcounts(ipkts, opkts) long *ipkts; long *opkts; { static char WHERE[] = "getpacketcounts"; /* Zero out the counts */ *ipkts = *opkts = 0; if (ioctl(sock, SIOCGIPKTS, (caddr_t)&ifr) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't SIOCGIPKTS for \"%s\", %m", device); unlock_pid(); exit(1); } *ipkts = (long)GETDATAVAL(ifr); if (ioctl(sock, SIOCGOPKTS, (caddr_t)&ifr) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't SIOCGOPKTS for \"%s\", %m", device); unlock_pid(); exit(1); } *opkts = (long)GETDATAVAL(ifr); } static int set_inactivity(max_inactivity) int max_inactivity; { static char WHERE[] = "set_inactivity"; int old; /* Get the old value */ if (ioctl(sock, SIOCGATIMEO, (caddr_t)&ifr) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't SIOCGATIMEO for \"%s\", %m", device); old = -1; } else old = GETDATAVAL(ifr); /* If the new time is negative, then just return the current value */ if (max_inactivity < 0) { d_log(DLOG_DIAG, WHERE, "Timeout for \"%s\" unchanged from %d", device, old); return old; } /* Set the inactivity timer */ SETDATAVAL(ifr, max_inactivity); if (ioctl(sock, SIOCSATIMEO, (caddr_t)&ifr) < 0) d_log(DLOG_GENERAL, WHERE, "Can't SIOCSATIMEO for \"%s\", %m", device); else if (max_inactivity) d_log(DLOG_INFO, WHERE, "Timeout for \"%s\" set to %d", device, max_inactivity); else d_log(DLOG_INFO, WHERE, "Timeout for \"%s\" disabled; must be brought down manually", device); return old; } static void writelog() { static char WHERE[] = "writelog"; FILE *F; long hours; long minutes; long seconds; /* Just in case... */ if (starttime == 0) return; if ((F = fopen(CALL_LOG, "a")) == NULL) { d_log(DLOG_DIAG, WHERE, "Can't open call log, %m"); return; } hours = duration / 3600; minutes = (duration - hours * 3600) / 60; seconds = duration - hours * 3600 - minutes * 60; (void)fprintf(F, "%-16.16s %-19.19s %02ld:%02ld:%02ld %s\n", sitename, ctime(&stoptime), hours, minutes, seconds, progname); (void)fclose(F); } /* ** Catch signal and exit. */ static void hangup(sig) int sig; { static char WHERE[] = "hangup"; long totalpkts; long endipkts; long endopkts; int disc; int status; /* Now ignore the signals since we're shutting down. */ (void)signal(SIGHUP, SIG_IGN); (void)signal(SIGTERM, SIG_IGN); d_log(DLOG_ALL, WHERE, "Process %d got signal %d for \"%s\"", mypid, sig, device); /* Let go of the lock file */ (void)uu_unlock(tty); unlock_pid(); /* Log the statistics */ (void)time(&stoptime); duration = stoptime - starttime; writelog(); getpacketcounts(&endipkts, &endopkts); totalpkts = (endipkts - startipkts) + (endopkts - startopkts); d_log(DLOG_INFO, WHERE, "Outbound interface \"%s\" up %ld seconds", device, duration); d_log(DLOG_DIAG, WHERE, "Inpackets = %ld, Outpackets = %ld, Average = %.2f packets/sec", endipkts - startipkts, endopkts - startopkts, totalpkts ? ((float)totalpkts) / ((float)duration) : 0); /* Restore the inactivity counter, disconnect and exit */ (void)set_inactivity(oldinactive); status = 0; /* Bring back the line discipline. */ disc = NTTYDISC; if (ioctl(dialfout, TIOCSETD, (caddr_t)&disc) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETD \"%s\", %m", device); status = 1; } /* Reset the TTY modes. */ if (ioctl(dialfout, TIOCSETP, (caddr_t)&oldsgtty) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETP \"%s\", %m", device); status = 1; } /* Drop DTR. */ if (ioctl(dialfout, TIOCCDTR, (caddr_t)0) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't TIOCCDTR \"%s\", %m", device); status = 1; } /* All done, report that we made it. */ d_log(DLOG_GENERAL, WHERE, "Disconnected \"%s\"", device); exit(status); } /* ** Set line to have the right discipline and modes. */ static int duconnect(device) char *device; { static char WHERE[] = "duconnect"; int dudisc; struct ifreq ifr; struct sgttyb sgtty; char *p; int uid; /* Get the current modes. */ if (ioctl(dialfout, TIOCGETP, (caddr_t)&sgtty) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't TIOCGETP on \"%s\", %m", device); return CALL_IOCTL_ERR; } oldsgtty = sgtty; /* Set the new modes. */ sgtty.sg_flags = RAW | ANYP; if (ioctl(dialfout, TIOCSETP, (caddr_t)&sgtty) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETP on \"%s\", %m", device); return CALL_IOCTL_ERR; } /* Find the device number and convert */ /* NEED TO BE MORE INTELLIGENT ABOUT THIS */ (void)strcpy(ifr.ifr_name, device); for (p = device; *p && !isdigit(*p); p++) ; #ifdef ifr_metric if (*p == '\0') { d_log(DLOG_GENERAL, WHERE, "Can't find unit number in \"%s\"", device); return CALL_BAD_IF; } ifr.ifr_metric = atoi(p); #endif /* Become root. */ uid = getuid(); if (setuid(0) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't setuid to root, %m"); return CALL_NOSETUID; } /* Change to the DIP discipline. */ dudisc = DUDISC; if (ioctl(dialfout, TIOCSETD, (caddr_t)&dudisc) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETD on \"%s\", %m -- is DIP configured?", device); return CALL_IOCTL_ERR; } if (ioctl(dialfout, SIOCSIFADDR, (caddr_t)&ifr) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't SIOCSIFADDR on \"%s\", %m -- is device installed?", device); return CALL_IOCTL_ERR; } d_log(DLOG_ALL, WHERE, "Did SIOCISFADDR on \"%s\"",device); (void)setuid(uid); return CALL_SUCCESS; } /* ** Get a modem from the list of usable ones for this system and return ** the first one that isn't already in use. NOTE: We must respect locks ** made by uucp, tip, cmdf et al */ static int find_modem(rp) REMOTE *rp; { register int i; for (i = 0; i < MAXDEVICES && rp->Lines[i][0]; i++) if (uu_lock(rp->Lines[i]) >= 0) return i; return -1; } /* ** Catch an alarm while waiting for the open to succeed. */ static void open_timeout() { longjmp(opentimeout, 1); /* NOTREACHED */ } static int makecall_real(rp) REMOTE *rp; { static char WHERE[] = "makecall"; char devtty[30]; FILE *fp; char logbuf[256]; struct sgttyb sgtty; int stat; char *tname; int i; /* Open our own path to the terminal and close the old connections */ if ((i = open("/dev/tty", O_RDONLY)) >= 0) { (void)ioctl(i, TIOCNOTTY, (caddr_t)0); (void)close(i); } (void)fclose(stdin); (void)fclose(stdout); /* Find a modem. */ if ((i = find_modem(rp)) < 0) { (void)sprintf(logbuf, "Can't find modem for \"%s\" -- check lock files.", rp->Sitename); failcall(rp->Device, logbuf); return CALL_PERMISSION; } (void)strcpy(tty, rp->Lines[i]); (void)strcpy(sitename, rp->Sitename); (void)strcpy(device, rp->Device); /* Set up exit handler. */ (void)signal(SIGHUP, hangup); (void)signal(SIGTERM, hangup); /* Set up a time-out handler. Main reason for the open timing-out is * because modem is off, or not configured correctly. */ (void)sprintf(devtty, "/dev/%s", tty); (void)signal(SIGALRM, open_timeout); if (setjmp(opentimeout)) { /* Open failed. */ (void)sprintf(logbuf, "Time-out opening modem \"%s\" for \"%s\"", devtty, rp->Sitename); failcall(rp->Device, logbuf); (void)uu_unlock(tty); return CALL_TTYTIMEOUT; } /* Open the modem port */ (void)alarm(OPEN_TIMEOUT); if ((dialfout = open(devtty, O_RDWR)) < 0) { (void)sprintf(logbuf, "Can't open modem \"%s\" for \"%s\", %s", devtty, rp->Sitename, strerror(errno)); failcall(rp->Device, logbuf); (void)uu_unlock(tty); return CALL_PERMISSION; } /* Turn off the timeout, record what we're using. */ (void)alarm(0); (void)signal(SIGALRM, SIG_DFL); (void)record_pid(rp->Device); /* Get the TTY modes. */ if (ioctl(dialfout, TIOCGETP, (caddr_t)&sgtty) < 0) { (void)sprintf(logbuf, "Can't TIOCGETP for \"%s\", %s", rp->Sitename, strerror(errno)); failcall(rp->Device, logbuf); (void)uu_unlock(tty); return CALL_IOCTL_ERR; } /* Set the new bits. */ if (rp->Speeds[i] > 0) sgtty.sg_ispeed = sgtty.sg_ospeed = rp->Speeds[i]; sgtty.sg_flags |= CBREAK; sgtty.sg_flags &= ~ECHO; /* Set the new mode. */ if (ioctl(dialfout, TIOCSETP, (caddr_t)&sgtty) < 0) { (void)sprintf(logbuf, "Can't TIOCSETP for \"%s\", %s", rp->Sitename, strerror(errno)); failcall(rp->Device, logbuf); (void)uu_unlock(tty); return CALL_IOCTL_ERR; } /* Change process group, set hangup on close. */ if (ioctl(dialfout, TIOCHPCL, (caddr_t)&sgtty) < 0) { (void)sprintf(logbuf, "Can't TIOCHPCL for \"%s\", %s", rp->Sitename, strerror(errno)); failcall(rp->Device, logbuf); (void)uu_unlock(tty); return CALL_IOCTL_ERR; } /* Open up the modem port. */ if ((fp = fdopen(dialfout, "r+")) == NULL) { (void)sprintf(logbuf, "Can't fdopen modem port for \"%s\"", rp->Sitename); failcall(rp->Device, logbuf); (void)uu_unlock(tty); return CALL_PERMISSION; } /* Set up the name of the transaction file. */ tname = rp->Transcript[0] ? rp->Transcript : NULL; /* Now run the script. */ d_log(DLOG_GENERAL, WHERE, "Attempting connection to \"%s\" via \"%s\"", rp->Sitename, rp->Device); if (runscript(rp, fp, tname) < 0) { (void)sprintf(logbuf, "Script \"%s\" for \"%s\" failed", rp->Script, rp->Sitename); failcall(rp->Device, logbuf); (void)uu_unlock(tty); return CALL_FAIL; } /* Connection set up, set the line discipline. */ if ((stat = duconnect(rp->Device)) != CALL_SUCCESS) { (void)uu_unlock(tty); return stat; } /* Connection made - get things going */ d_log(DLOG_GENERAL, WHERE, "Connected to \"%s\" via \"%s\"", sitename, device); return CALL_SUCCESS; } int makecall(rp) REMOTE *rp; { static char WHERE[] = "makecall"; int uptime; int old_if; int old_soft; /* Record the PID */ mypid = getpid(); if (makecall_real(rp) != CALL_SUCCESS) return; /* Create a socket for gathering info. */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { d_log(DLOG_GENERAL, WHERE, "Can't create socket for \"%s\", %m", device); unlock_pid(); exit(1); } /* Set up info, collect starting stats. */ (void)strcpy(ifr.ifr_name, device); oldinactive = set_inactivity(rp->Inactivity); (void)time(&starttime); getpacketcounts(&startipkts, &startopkts); d_log(DLOG_DIAG, WHERE, "Outbound interface \"%s\" starting ipkts = %ld, opkts = %ld", device, startipkts, startopkts); /* Now keep tabs on the interface */ for (old_if = old_soft = 0, uptime = 0; ; ) { /* See if the IF flags changed. */ if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) d_log(DLOG_GENERAL, WHERE, "Can't SIOCGIFFLAGS, %m"); else if (ifr.ifr_flags != old_if) { d_log(DLOG_ALL, WHERE, "\"%s\" IF flags changed from 0x%04x to 0x%04x", device, old_if, ifr.ifr_flags); old_if = ifr.ifr_flags; } /* See if the soft flags changed. */ if (ioctl(sock, SIOCGSOFTFLAGS, (caddr_t)&ifr) < 0) d_log(DLOG_GENERAL, WHERE, "Can't SIOCGSOFTFLAGS, %m"); else if (GETDATAVAL(ifr) != old_soft) { d_log(DLOG_ALL, WHERE, "\"%s\" SOFT flags changed from 0x%04x to 0x%04x", device, old_soft, GETDATAVAL(ifr)); old_soft = GETDATAVAL(ifr); } (void)sleep(UPTIME_INTERVAL * 60); uptime += UPTIME_INTERVAL; d_log(DLOG_INFO, WHERE, "Outbound interface \"%s\" up %d minutes", device, uptime); } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.