home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
300-399
/
ff319.lzh
/
CNewsSrc
/
uupc.lzh
/
uupc
/
dcpgpkt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-01-16
|
16KB
|
727 lines
/* dcpgpkt.c
*
* Revised edition of dcp
*
* Stuart Lynne May/87
*
* Copyright (c) Richard H. Lamb 1985, 1986, 1987
* Changes Copyright (c) Stuart Lynne 1987
*
* $Id: dcpgpkt.c,v 1.2 90/01/16 10:25:07 crash Exp Locker: crash $
*/
#ifndef lint
static char RCSid[] = "$Id: dcpgpkt.c,v 1.2 90/01/16 10:25:07 crash Exp Locker: crash $";
#endif /* lint */
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987
*
* 3-window "g" ptotocol
*
* Thanks go to John Gilmore for sending me a copy of Greg Chesson's
* UUCP protocol description -- Obviously invaluable.
*
* Thanks also go to Andrew Tannenbaum for the section on Sliding window
* protocols with a program example in his "Computer Networks" book.
*/
#include "dcp.h"
#define PKTSIZE 64
#define PKTSIZ2 2
#define HDRSIZE 6
#define MAXTRY 4
#define MAXERR 200 /* Dont want to quit in a middle of a long file*/
#define TIMEOUT 4 /* could be longer */
#define KPKT 1024/PKTSIZE
#define POK -1
#define SWINDOW 3 /* fixed now, U make it variable */
#define RWINDOW 3
#define NBUF 8 /* always SAME as MAXSEQ ? */
#define MAXSEQ 8
#define between(a,b,c) ((a<=b && b<c) || (c<a && a<=b) || (b<c && c<a))
/* packet defin */
static int rwl, swl, swu, rwu, nerr, nbuffers, npkt, irec, timeout;
static int GOT_SYNC, GOT_HDR;
static int fseq[NBUF], outlen[NBUF], inlen[NBUF], arr[NBUF];
static char outbuf[NBUF][PKTSIZE+1], inbuf[NBUF][PKTSIZE+1];
static unsigned char grpkt[HDRSIZE+1];
static long ftimer[NBUF], acktmr, naktmr;
/******************SUB SUB SUB PACKET HANDLER************/
gopenpk()
{
int i, j, n1, n2, len;
char tmp[PKTSIZE+1];
pktsize = PKTSIZE; /* change it later after the init */
msgtime = MSGTIME; /* not sure I need this for "g" proto */
/* initialize proto parameters */
swl = nerr = nbuffers = npkt = 0;
swl = swu = 1;
rwl = 0;
rwu = RWINDOW - 1;
for (i = 0; i < NBUF; i++) {
ftimer[i] = 0;
arr[i] = FALSE;
}
GOT_SYNC = GOT_HDR = FALSE;
/* 3-way handshake */
timeout = 1; /* want some timeout capability here */
gspack(7, 0, 0, 0, tmp);
rsrt:
if (nerr >= MAXERR)
#if 1
printmsg( 0, "excessive errors (%d) at pkt %d", nerr, npkt );
nerr = 0;
#else
return(-1);
#endif
/*
* INIT sequence. Easy fix for variable pktsize and windows.
* I didn't since all the machines I talk to use W=3 PKTSZ=64
*
* If you do this make sure to reflect the changes in "grpack"
* and "gspack".
*/
switch (i = grpack(&n1, &n2, &len, tmp)) {
case 7:
gspack(6, 0, 0, 0, tmp);
goto rsrt;
case 6:
gspack(5, 0, 0, 0, tmp);
goto rsrt;
case 5:
break;
default:
nerr++;
printmsg(4, "error #%d (%d) at pkt %d", nerr, i, npkt);
printmsg(5, " grpack(%d, %d, %d, :%s:)", n1,n2,len, prt(tmp,len));
gspack(7, 0, 0, 0, tmp);
goto rsrt;
}
nerr = 0;
return(0); /* channel open */
}
gclosepk()
{
int i;
char tmp[PKTSIZE+1];
timeout = 1;
for (i = 0; i < MAXTRY; i++) {
gspack(CLOSE, 0, 0, 0, tmp);
if (gmachine() == CLOSE)
break;
}
printmsg( 0, "number of errors %d and pkts xfered %d", nerr, npkt );
return(0);
}
/*
* ggetpkt
*
* description:
* Gets no more than a packet's worth of data from the "packet i/o
* state machine". May have to periodically run the pkt machine to
* get some packets.
*
* on input: dont care
* getpkt( char *data, int *len)
*
* on return: data+\0 and length in len.
* ret(0) if all's well
* ret(-1) if problems (fail)
*/
ggetpkt(cdata, len)
int *len;
char cdata[];
{
int i2;
irec = 1;
timeout = 0;
/* WAIT FOR THE DESIRED PACKET */
while ((arr[rwl]) == FALSE)
if (gmachine() != POK)
return(-1);
/* GOT A PKT ! */
i2 = rwl; /* <-- mod(,rwindow) for > 8 seq no.s */
*len = inlen[i2];
memcpy(cdata, inbuf[i2], *len);
arr[i2] = FALSE;
rwu = (1 + rwu) % MAXSEQ; /* bump rec window */
npkt++;
return(0);
}
/*
*
* gsendpkt
*
* description:
* Put at most a packet's worth of data in the pkt state
* machine for transmission.
* May have to run the pkt machine a few times to get
* an available output slot.
*
* on input: gsendpkt(char *data, int len, int flg)
* len=length of data in data.
* flg=2 just send the packet with no wait for ack.
* flg>0 zero out the unused part of the buffer. (for UUCP "msg" pkts)
* flg=0 normal data
*
* return:
* ret(0) if alls well
* ret(-1) if problems (fail)
*/
gsendpkt(cdata, len, flg)
int len, flg;
char *cdata;
{
int i, i1;
long ttmp;
irec = 0;
timeout = 0; /* non-blocking reads */
/*
* WAIT FOR INPUT i.e. if we've sent SWINDOW pkts and none have been
* acked, wait for acks
*/
while (nbuffers >= SWINDOW)
if (gmachine() != POK)
return(-1);
i1 = swu; /* <-- mod(,rwindow) for > 8 seq no.s */
/*
* PLACE PACKET IN TABLE AND MARK UNACKED
* fill with zeros or not
*
* [FJE] Changed to use memcpy/memset instead of strcpy!
*/
if (flg) {
if (!len) /* Currently, all flg!=0 calls are len==0 */
len = strlen(cdata);
memcpy(outbuf[i1], cdata, len);
memset(outbuf[i1]+len, (int) '\0', PKTSIZE-len);
i = len = PKTSIZE;
} else { /* flg==0 only inside sdata() */
memcpy(outbuf[i1], cdata, len);
outbuf[i1][len] = '\0';
}
/* mark packet */
outlen[i1] = len;
ftimer[i1] = time(&ttmp);
fseq[i1] = swu;
swu = (1 + swu) % MAXSEQ; /* bump send window */
nbuffers++;
npkt++;
/* send it */
gspack(DATA, rwl, fseq[i1], outlen[i1], outbuf[i1]);
/*
* send it once then let the pkt machine take it.
* wouldn't need this for multitasking systems
sl = gmachine();
*/
return(0);
}
/************ packet machine ****** RH Lamb 3/87 */
/*
* Ideally we would like to fork this process off in an infinite loop
* and send and receive pkts thru "inbuf" and "outbuf". Can't do this in
* MS-DOS so we setup "getpkt" and "sendpkt" to call this routine often
* and return only when the input buffer is empty thus "blocking" the
* pkt-machine task.
*/
gmachine()
{
int rack, rseq, rlen, i1, i2, dflg;
char rdata[PKTSIZE+1];
long ttmp, itmp;
#ifdef FJE
short time_err = 0;
#endif /* FJE */
reply:
printmsg( 6, "*send %d<W<%d, rec %d<W<%d, err %d",
swl, swu, rwl, rwu, nerr );
/*
* waiting for ACKs for swl to swu-1. Next pkt to send=swu
* rwl=expected pkt
*/
if (nerr >= MAXERR)
goto close;
dflg = 0;
switch (grpack(&rack, &rseq, &rlen, rdata)) {
case CLOSE:
printmsg( 5, "**got CLOSE");
goto close;
case NAK:
nerr++;
#ifdef FJE
time_err = 0;
#endif /* FJE */
acktmr = naktmr = 0; /* stop ack/nak timer */
printmsg( 5, "**got NAK %d", rack );
nloop:
if (between(swl, rack, swu)) { /* resend rack->(swu-1) */
i1 = rack;
gspack(DATA, rwl, rack, outlen[i1], outbuf[i1]);
printmsg( 5, "***resent %d", rack );
ftimer[i1] = time(&ttmp);
rack = (1 + rack) % MAXSEQ;
goto nloop;
}
if (dflg)
return(POK);
goto reply; /* any other stuff ? */
case EMPTY:
printmsg( 5, "**got EMPTY" );
itmp = time(&ttmp);
if (acktmr)
if ((itmp - acktmr) >= TIMEOUT) { /* ack timed out */
gspack(ACK, rwl, 0, 0, rdata);
#ifdef FJE
time_err++;
#endif /* FJE */
acktmr = itmp;
}
if (naktmr)
if ((itmp - naktmr) >= TIMEOUT) { /* nak timed out */
gspack(NAK, rwl, 0, 0, rdata);
#ifdef FJE
time_err++;
#endif /* FJE */
naktmr = itmp;
}
/* resend any timed out un-acked pkts */
#ifdef FJE
/*
* Wait up to 5 minutes.
*/
if (time_err > 300 / TIMEOUT) {
printmsg( 0, "too many timeouts; closing connection" );
goto close;
}
#endif /* FJE */
for (i2 = swl; between(swl, i2, swu); i2 = (1 + i2) % MAXSEQ) {
acktmr = naktmr = 0; /* reset ack/nak */
i1 = i2;
printmsg( 5, "--->seq,elapst %d %ld", i2, (itmp - ftimer[i1]) );
if ((itmp - ftimer[i1]) >= TIMEOUT) {
printmsg( 5, "***timeout %d", i2 );
/*
* since "g" is "go-back-N", when we time out we
* must send the last N pkts in order. The generalized
* sliding window scheme relaxes this reqirement.
*/
nerr++;
dflg = 1; /* same hack */
rack = i2;
goto nloop;
}
}
return(POK);
case ACK:
#ifdef FJE
time_err = 0;
#endif /* FJE */
printmsg( 5, "**got ACK %d", rack );
acktmr = naktmr = 0; /* disable ack/nak's */
aloop:
if (between(swl, rack, swu)) { /* S<-- -->(S+W-1)%8 */
printmsg( 5, "***ACK %d", swl );
ftimer[swl] = 0;
nbuffers--;
swl = (1 + swl) % MAXSEQ;
dflg = 1; /* same hack; sl */
goto aloop;
}
if (dflg)
return(POK); /* hack for non-mutlitask systems */
/* to empty "inbuf[]" */
goto reply;
case DATA:
#ifdef FJE
time_err = 0;
#endif /* FJE */
printmsg( 5, "**got DATA %d %d", rack, rseq );
i1 = (1 + rwl) % MAXSEQ; /* (R+1)%8 <-- -->(R+W)%8 */
i2 = (1 + rwu) % MAXSEQ;
if (between(i1, rseq, i2)) {
if (i1 == rseq) {
i1 = rseq;
arr[i1] = TRUE;
inlen[i1] = rlen;
memcpy(inbuf[i1], rdata, rlen);
rwl = (rwl + 1) % MAXSEQ;
printmsg( 5, "***ACK d %d", rwl );
gspack(ACK, rwl, 0, 0, rdata);
acktmr = time(&ttmp); /* enable ack/nak tmout */
dflg = 1; /* ret to call when finished */
/* (not in a multitask system) */
} else {
nerr++;
printmsg( 5, "***unexpected %d on %d", rseq, rwl );
}
} else {
nerr++;
printmsg( 5, "***wrong seq %d", rseq );
}
goto aloop;
case ERROR:
nerr++;
#ifdef FJE
time_err = 0;
#endif /* FJE */
printmsg( 5, "**got BAD CHK" );
gspack(NAK, rwl, 0, 0, rdata);
naktmr = time(&ttmp); /* set nak timer */
printmsg( 5, "***NAK d %d", rwl );
goto reply;
default:
printmsg( 5, "**got SCREW UP" );
goto reply; /* ignore it */
}
close:
gspack(CLOSE, 0, 0, 0, rdata);
return(CLOSE);
}
/*************** FRAMING *****************************/
/*
* send a packet
*
* nt2=type nt3=pkrec nt4=pksent
* len=length<=PKTSIZE cnt1= data * ret(0) always
*/
gspack(nt2, nt3, nt4, len, cnt1)
int nt2, nt3, nt4, len;
char cnt1[];
{
unsigned int check, i;
unsigned char c2, pkt[HDRSIZE+1], dpkerr[10];
if (len > 64)
len = 64;
if (len == 0)
cnt1[0] = '\0';
#if 0
/**Link testing mods- create artificial errors ***/
printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
gets(dpkerr);
if(dpkerr[0] == 's') { sscanf(&dpkerr[1],"%d",&nt4); }
/** End Link testing mods ***/
#endif
printmsg( 5, "send packet type %d, num=%d, n=%d, len=%d",
nt2, nt3, nt4, len );
printmsg( 5, "data =\n|%s|", cnt1 );
c2 = '\0';
pkt[0] = '\020';
pkt[4] = nt2 << 3;
nt2 &= 7;
switch (nt2) {
case 1:
break; /* stop protocol */
case 2:
pkt[4] += nt3;
break; /* reject */
case 3:
break;
case 4:
pkt[4] += nt3;
break; /* ack */
case 5:
pkt[4] += SWINDOW;
break; /* 3 windows */
case 6:
pkt[4] += 1;
break; /* pktsiz = 64 (1) */
case 7:
pkt[4] += SWINDOW;
break; /* 3 windows */
case 0:
pkt[4] += 0x80 + nt3 + (nt4 << 3);
c2 = (PKTSIZE - len) & 0xff;
/*
* haven't set it up for VERY LONG pkts with a few
* bytes yet (-128)
*/
if (c2) { /* short packet handling */
pkt[4] += 0x40; /* if len < PKTSIZE */
for (i = PKTSIZE - 1; i > 0; i--)
cnt1[i] = cnt1[i-1];
cnt1[0] = c2;
}
break;
}
pkt[4] &= 0xff;
if (nt2) {
pkt[1] = 9; /* control packet size = 0 (9) */
check = (0xaaaa - pkt[4]) & 0xffff;
} else {
pkt[1] = PKTSIZ2; /* data packet size = 64 (2) */
check = checksum(cnt1, PKTSIZE);
i = pkt[4]; /* req'd on PC for XOR high bits */
i &= 0xff;
check = (check ^ i) & 0xffff;
check = (0xaaaa - check) & 0xffff;
}
pkt[2] = check & 0xff;
pkt[3] = (check >> 8) & 0xff;
pkt[5] = (pkt[1] ^ pkt[2] ^ pkt[3] ^ pkt[4]) & 0xff;
#if 0
/*** More Link testing MODS ******/
switch(dpkerr[0]) {
case 'e': cnt1[10] = -cnt1[10];
break;
case 'h': pkt[5] = -pkt[5];
break;
case 'l': return;
case 'p': swrite(pkt,HDRSIZE);
if(pkt[1] != 9) swrite(cnt1,PKTSIZE-3);
return;
default: break;
}
/****** End Link Testing Mods **********/
#endif
swrite(pkt, HDRSIZE); /* header is 6-bytes long */
#if 0
write(flog,pkt,HDRSIZE);
#endif
if (pkt[1] != 9) {
swrite(cnt1, PKTSIZE); /* data is always 64 bytes long */
#if 0
write(flog,cnt1,PKTSIZE);
#endif
}
}
/*
* read packet
*
* on return: nt3=pkrec nt4=pksent
* len=length<=PKTSIZE cnt1=data * ret(type) ok;
* ret(EMPTY) input buf empty;
* ret(ERROR) bad header;
* ret(EMPTY) lost pkt timeout;
* ret(ERROR) checksum error;
* ret(-5) ?
*
* NOTE:
*
* sread(buf,n,timeout)
* while(TRUE) {
* if(# of chars available >= n) (without dec internal counter)
* read n chars into buf (decrement internal char counter)
* break
* else
* if(time>timeout) break
* }
* return(# of chars available)
*/
grpack(nt3, nt4, len, cnt1)
int *nt3, *nt4, *len;
char cnt1[];
{
unsigned int nt1, check, checkchk, i;
unsigned char c, c2;
int ii;
#ifdef FJE
Chk_Abort(0L);
#endif /* FJE */
if (GOT_SYNC)
goto get_hdr;
if (GOT_HDR)
goto get_data;
c = '\0';
while ((c & 0x7f) != '\020')
if (sread(&c, 1, timeout) == 0)
return(EMPTY);
GOT_SYNC = TRUE;
get_hdr:
if (sread(&grpkt[1], HDRSIZE - 1, timeout) < (HDRSIZE - 1))
return(EMPTY);
GOT_SYNC = FALSE;
#if 0
i = grpkt[1] ^ grpkt[2] ^ grpkt[3] ^ grpkt[4] ^ grpkt[5];
#else
i = (unsigned)grpkt[1] ^ (unsigned)grpkt[2] ^
(unsigned)grpkt[3] ^ (unsigned)grpkt[4] ^
(unsigned)grpkt[5];
#endif
i &= 0xff;
printmsg( 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
if (i) {
printmsg( 0, "**** bad header ****" );
/*
* I'm not sure whether "g" considers it an empty or error
*/
return(ERROR);
}
GOT_HDR = TRUE;
if ((grpkt[1] &= 0x7f) == 9) { /* control packet */
*len = 0;
c = grpkt[4] & 0xff;
nt1 = c >> 3;
*nt3 = c & 7;
*nt4 = 0;
check = 0;
checkchk = 0;
cnt1[*len] = '\0';
GOT_HDR = FALSE;
} else { /* data packet */
if (grpkt[1] != PKTSIZ2)
return(-5); /* can't handle other than 64 */
get_data:
if (sread(cnt1, PKTSIZE, timeout) < PKTSIZE)
return(EMPTY);
GOT_HDR = FALSE;
nt1 = 0;
c2 = grpkt[4] & 0xff;
c = c2 & 0x3f;
*nt4 = c >> 3;
*nt3 = c & 7;
i = grpkt[3];
i = (i << 8) & 0xff00;
check = grpkt[2];
check = i | (check & 0xff);
checkchk = checksum(cnt1, PKTSIZE);
i = grpkt[4] | 0x80;
i &= 0xff;
checkchk = 0xaaaa - (checkchk ^ i);
checkchk &= 0xffff;
if (checkchk != check) {
printmsg( 4, "*** checksum error ***" );
return(ERROR);
}
*len = PKTSIZE;
/*
* haven't set it up for very long pkts yet (>128) RH Lamb
*/
if (c2 & 0x40) {
ii = (cnt1[0] & 0xff);
*len = (*len - ii) & 0xff;
for (ii = 0; ii < *len; ii++)
cnt1[ii] = cnt1[ii+1];
}
cnt1[*len] = '\0';
}
printmsg( 5, "rec packet type %d, num=%d, n=%d, len=%d",
nt1, *nt3, *nt4, *len);
printmsg( 6, " checksum rec = %x comp = %x, data=\n|%s|",
check, checkchk, cnt1);
ii = nt1;
return(ii);
}
unsigned checksum(data, len)
int len;
char data[];
{
unsigned int i, j, tmp, chk1, chk2;
chk1 = 0xffff;
chk2 = 0;
j = len;
for (i = 0; i < len; i++) {
if (chk1 & 0x8000) {
chk1 <<= 1;
chk1++;
} else {
chk1 <<= 1;
}
tmp = chk1;
chk1 += (data[i] & 0xff);
chk2 += chk1 ^ j;
if ((chk1 & 0xffff) <= (tmp & 0xffff))
chk1 ^= chk2;
j--;
}
return(chk1 & 0xffff);
}
/*
* gwrmsg
* send a null terminated string out
*/
gwrmsg( typ, buf )
char typ;
char *buf; /* null terminated */
{
return( 0 );
}
/*
* grdmsg
* read a null terminated string
*/
grdmsg( buf )
char *buf;
{
return( 0 );
}
/*
* gwrdata
* read a file and send it out
*/
gwrdata( f )
{
return( 0 );
}
/*
* grrdata
* read in data and send to file
*/
grrdata( f )
{
return( 0 );
}
/*
* grdblk
* read a block of data in
*/
grdblk( blk, len )
{
return( 0 );
}
/*
* gwrblk
* write out a block of data
*/
gwrblk( blk, len )
{
return( 0 );
}