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.