home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware 1 2 the Maxx
/
sw_1.zip
/
sw_1
/
LAN
/
S920603.ZIP
/
DIALER.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-15
|
9KB
|
399 lines
/* Automatic SLIP/PPP line dialer.
*
* Copyright 1991 Phil Karn, KA9Q
*
* Mar '91 Bill Simpson & Glenn McGregor
* completely re-written;
* human readable control file;
* includes wait for string, and speed sense;
* dials immediately when invoked.
* May '91 Bill Simpson
* re-ordered command line;
* allow dial only;
* allow inactivity timeout without ping.
* Sep '91 Bill Simpson
* Check known DTR & RSLD state for redial decision
* Mar '92 Phil Karn
* autosense modem control stuff removed
* Largely rewritten to do demand dialing
*/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "proc.h"
#include "iface.h"
#include "netuser.h"
#include "n8250.h"
#include "asy.h"
#include "tty.h"
#include "socket.h"
#include "cmdparse.h"
#include "devparam.h"
#include "files.h"
#include "main.h"
#include "trace.h"
#include "commands.h"
static int redial __ARGS((struct iface *ifp,char *file));
static void dropline __ARGS((void *));
static void dropit(int,void *,void *);
static int dodial_control __ARGS((int argc,char *argv[],void *p));
static int dodial_send __ARGS((int argc,char *argv[],void *p));
static int dodial_speed __ARGS((int argc,char *argv[],void *p));
static int dodial_status __ARGS((int argc,char *argv[],void *p));
static int dodial_wait __ARGS((int argc,char *argv[],void *p));
static struct cmds dial_cmds[] = {
"", donothing, 0, 0, "",
"control", dodial_control, 0, 2, "control up | down",
"send", dodial_send, 0, 2,
"send \"string\" [<milliseconds>]",
"speed", dodial_speed, 0, 2, "speed <bps>",
"status", dodial_status, 0, 2, "status up | down",
"wait", dodial_wait, 0, 2,
"wait <milliseconds> [ \"string\" [speed] ]",
NULLCHAR, NULLFP, 0, 0, "Unknown command",
};
/*
* dial <iface> <seconds> <raisefile> <dropfile>
* dial <iface>
* dial <iface> 0
*/
int
dodialer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp;
struct asy *ap;
int32 timeout;
if((ifp = if_lookup(argv[1])) == NULLIF){
printf("Interface %s unknown\n",argv[1]);
return 1;
}
if(ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp){
printf("Interface %s not asy port\n",argv[1]);
return 1;
}
ap = &Asy[ifp->dev];
if(argc < 3){
printf("%s: %s",ifp->name,(ap->msr & MSR_RLSD) ? "UP":"DOWN");
printf(", idle timer %ld/%ld",read_timer(&ap->idle)/1000L,
dur_timer(&ap->idle)/1000L);
if(ap->actfile != NULLCHAR)
printf(", up script: %s",ap->actfile);
if(ap->dropfile != NULLCHAR)
printf(", down script: %s\n",ap->dropfile);
else
printf("\n");
printf("Calls originated %ld, carrier up transitions %ld\n",
ap->originates,ap->answers);
printf("Calls timed out %ld, carrier down transitions %ld\n",
ap->localdrops,ap->remdrops);
return 0;
}
timeout = atol(argv[2]) * 1000L;
if(timeout != 0 && argc < 5){
printf("Usage: dial <iface> <timeout> <raisefile> <dropfile>\n");
printf(" dial <iface> 0\n");
return 1;
}
if(!ap->rlsd){
printf("Must set 'r' flag at attach time\n");
return 1;
}
stop_timer(&ap->idle);
set_timer(&ap->idle,timeout);
ap->idle.func = dropline;
ap->idle.arg = ifp;
if(ap->actfile != NULLCHAR){
free(ap->actfile);
ap->actfile = NULLCHAR;
}
if(ap->dropfile != NULLCHAR){
free(ap->dropfile);
ap->dropfile = NULLCHAR;
}
if(timeout != 0){
ap->actfile = strdup(argv[3]);
ap->dropfile = strdup(argv[4]);
start_timer(&ap->idle);
}
return 0;
}
void
dialer_kick(asyp)
struct asy *asyp;
{
int backoff = -1;
int pw;
stop_timer(&asyp->idle);
while(asyp->rlsd && (asyp->msr & MSR_RLSD) == 0
&& asyp->actfile != NULLCHAR){
/* Line down, we need to redial
* But if it's failing, perform random binary
* exponential backoff
*/
if(backoff++ >= 0){
alarm(1000L*random(30L << backoff));
pw = pwait(&asyp->rlsd);
alarm(0L);
if(pw == 0)
continue; /* CD changed, maybe we got called */
}
asyp->originates++;
redial(asyp->iface,asyp->actfile);
}
}
/* Called when idle line timer expires -- executes script to drop line */
static void
dropline(p)
void *p;
{
/* Fork this off to prevent wedging the timer task */
newproc("dropit",512,dropit,0,p,NULL,0);
}
static void
dropit(i,p,u)
int i;
void *p;
void *u;
{
struct iface *ifp = p;
struct asy *ap;
ap = &Asy[ifp->dev];
if(ap->msr & MSR_RLSD){
ap->localdrops++;
redial(ifp,ap->dropfile); /* Drop only if still up */
}
}
/* execute dialer commands
* returns: -1 fatal error, 0 OK, 1 try again
*/
static int
redial(ifp,file)
struct iface *ifp;
char *file;
{
char *inbuf, *intmp;
FILE *fp;
int (*rawsave) __ARGS((struct iface *,struct mbuf *));
int result = 0;
if((fp = fopen(file,READ_TEXT)) == NULLFILE){
if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
tprintf(ifp,"redial: can't read %s\n",file);
return -1;
}
/* Save output handler and temporarily redirect output to null */
if(ifp->raw == bitbucket){
if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
tprintf(ifp,"redial: tip or dialer already active on %s\n",ifp->name);
return -1;
}
if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
tprintf(ifp,"Dialing on %s\n\n",ifp->name);
/* Save output handler and temporarily redirect output to null */
rawsave = ifp->raw;
ifp->raw = bitbucket;
/* Suspend the packet input driver. Note that the transmit driver
* is left running since we use it to send buffers to the line.
*/
suspend(ifp->rxproc);
inbuf = mallocw(BUFSIZ);
intmp = mallocw(BUFSIZ);
while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
strcpy(intmp,inbuf);
rip(intmp);
log(-1,"%s dialer: %s",ifp->name,intmp);
if((result = cmdparse(dial_cmds,inbuf,ifp)) != 0){
if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
tprintf(ifp,"input line: %s",intmp);
break;
}
}
free(inbuf);
free(intmp);
fclose(fp);
if(result == 0){
ifp->lastsent = ifp->lastrecv = secclock();
}
ifp->raw = rawsave;
resume(ifp->rxproc);
if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
tprintf(ifp,"\nDial %s complete\n",ifp->name);
return result;
}
static int
dodial_control(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
int param;
if ( ifp->ioctl == NULL )
return -1;
if ( (param = devparam( argv[1] )) == -1 )
return -1;
(*ifp->ioctl)( ifp, param, TRUE, atol( argv[2] ) );
return 0;
}
static int
dodial_send(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
struct mbuf *bp;
if(argc > 2){
/* Send characters with inter-character delay
* (for dealing with prehistoric Micom switches that
* can't take back-to-back characters...yes, they
* still exist.)
*/
char *cp;
int32 cdelay = atol(argv[2]);
for(cp = argv[1];*cp != '\0';cp++){
asy_write(ifp->dev,cp,1);
pause(cdelay);
}
} else {
if (ifp->trace & IF_TRACE_RAW)
raw_dump( ifp, IF_TRACE_OUT, bp );
asy_write(ifp->dev,argv[1],strlen(argv[1]));
}
return 0;
}
static int
dodial_speed(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
if ( argc < 2 ) {
if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
tprintf(ifp,"current speed = %u bps\n", Asy[ifp->dev].speed);
return 0;
}
return asy_speed( ifp->dev, (int16)atol( argv[1] ) );
}
static int
dodial_status(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
int param;
if ( ifp->iostatus == NULL )
return -1;
if ( (param = devparam( argv[1] )) == -1 )
return -1;
(*ifp->iostatus)( ifp, param, atol( argv[2] ) );
return 0;
}
static int
dodial_wait(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
register int c = -1;
alarm(atol(argv[1]));
if(argc == 2){
while((c = get_asy(ifp->dev)) != -1 ){
c &= 0x7f;
if(ifp->trace & IF_TRACE_IN){
fputc(c,ifp->trfp);
fflush(ifp->trfp);
}
}
alarm(0L);
return 0;
} else {
register char *cp = argv[2];
while(*cp != '\0' && (c = get_asy(ifp->dev)) != -1){
c &= 0x7f;
if(ifp->trace & IF_TRACE_IN){
fputc(c,ifp->trfp);
fflush(ifp->trfp);
}
if(*cp++ != c){
cp = argv[2];
}
}
if(argc > 3){
if(stricmp( argv[3], "speed") == 0){
int16 speed = 0;
while((c = get_asy(ifp->dev)) != -1){
c &= 0x7f;
if(ifp->trace & IF_TRACE_IN){
fputc(c,ifp->trfp);
fflush(ifp->trfp);
}
if(isdigit(c)){
speed *= 10;
speed += c - '0';
} else {
alarm(0L);
return asy_speed( ifp->dev, speed );
}
}
} else {
return -1;
}
}
}
alarm(0L);
return (c == -1);
}