ftp.nice.ch/peanuts/GeneralData/Documents/user-groups/rmNUG/dialupip2.0.tar.gz#/src/diald/makecall.c

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.