home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d1xx
/
d109
/
uupc.lha
/
UUpc
/
Source
/
dcpgpkt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-10-28
|
15KB
|
619 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
*/
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* 3-window "g" ptotocol */
/* Thanks got 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 Siding window
protocols with a program example in his "Computer Networks" book
MAINTENANCE NOTES:
25Aug87 - Allow for up to 7 windows - Jal
*/
#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 MAXWINDOW 7
#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, GOT_SYNC, GOT_HDR;
static int fseq[NBUF], outlen[NBUF], inlen[NBUF], arr[NBUF];
static int nwindows;
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 = MAXWINDOW - 1;
nwindows = MAXWINDOW;
for (i = 0; i < NBUF; i++) {
ftimer[i] = 0;
arr[i] = FALSE;
}
GOT_SYNC = GOT_HDR = FALSE;
/* 3-way handshake */
timeout = 2; /* want some timeout capability here */
gspack(7, 0, 0, 0, tmp);
rsrt:
if (nerr >= MAXERR)
return(-1);
/* INIT sequence. Easy fix for variable pktsize and windows. */
/* I didnt 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 (grpack(&n1, &n2, &len, tmp)) {
case 7:
gspack(6, 0, 0, 0, tmp);
nwindows = n1;
if ( nwindows > MAXWINDOW )
nwindows = MAXWINDOW;
rwu = nwindows - 1;
goto rsrt;
case 6:
gspack(5, 0, 0, 0, tmp);
goto rsrt;
case 5:
break;
default:
nerr++;
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(data,&len) char *data int len
* on return: data+\0 and length in len. ret(0) if alls 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 larger than 8 seq no.s */
*len = inlen[i2];
strncpy(cdata, inbuf[i2], *len);
arr[i2] = FALSE;
rwu = (1 + rwu) % MAXSEQ; /* bump rec window */
npkt++;
return(0);
}
/*
*
* sendpkt
*
***** description: Put at most a packet's worth of data in the pkt state
**** machine for xmission.
***** May have to run the pkt machine a few times to get
***** an available output slot.
*
* on input: char *data int len,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 weve sent SWINDOW pkts and none have been */
/* acked, wait for acks */
while (nbuffers >= nwindows)
if (gmachine() != POK)
return(-1);
i1 = swu; /* <--If we ever have more than 8 seq no.s, must mod() here*/
/* PLACE PACKET IN TABLE AND MARK UNACKED */
/* fill with zeros or not */
if (flg) {
strcpy(outbuf[i1], cdata);
len = PKTSIZE;
for (i = strlen(cdata); i < len; i++)
outbuf[i1][i] = '\0';
} else {
strncpy(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. wouldnt need this for */
/* mtasking systems */
/* sl gmachine(); */
return(0);
}
/************ packet machine ****** RH Lamb 3/87 */
/* Idealy we would like to fork this process off in an infinite loop */
/* and send and rec pkts thru "inbuf" and "outbuf". Cant 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;
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 */
printmsg( 7, "Kbytes transfered %d errors %d\r", npkt / KPKT, nerr );
if (nerr >= MAXERR)
goto close;
dflg = 0;
switch (grpack(&rack, &rseq, &rlen, rdata)) {
case CLOSE:
printmsg( 5, "**got CLOSE");
goto close;
case NAK:
nerr++;
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);
acktmr = itmp;
}
if (naktmr)
if ((itmp - naktmr) >= TIMEOUT) { /*nak timed out*/
gspack(NAK, rwl, 0, 0, rdata);
naktmr = itmp;
}
/* resend any timed out un-acked pkts */
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 reqirment */
nerr++;
dflg = 1; /* same hack */
rack = i2;
goto nloop;
}
}
return(POK);
case ACK:
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-mtask sys's */
/* to empty "inbuf[]" */
goto reply;
case DATA:
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;
strncpy(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; /*return to call when finished*/
/* in a mtask system, unneccesary */
} else {
nerr++;
printmsg( 5, "***unexpect %d ne %d", rseq, rwl );
}
} else {
nerr++;
printmsg( 5, "***wrong seq %d", rseq );
}
goto aloop;
case ERROR:
nerr++;
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);
}
/**/
/*************** FRAMMING *****************************/
/*
*
*
* 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';
/**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 ***/
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] += nwindows;
break;
case 6:
pkt[4] += 1;
break; /* pktsiz = 64 (1) */
case 7:
pkt[4] += MAXWINDOW;
break;
case 0:
pkt[4] += 0x80 + nt3 + (nt4 << 3);
c2 = (PKTSIZE - len) & 0xff;
/* havnt 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];/* got to do this on PC for ex-or 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;
/***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 **********/
swrite(pkt, HDRSIZE); /* header is 6-bytes long */
/* write(flog,pkt,HDRSIZE); */
if (pkt[1] != 9) {
swrite(cnt1, PKTSIZE); /* data is always 64
bytes long */
/* write(flog,cnt1,PKTSIZE); */
}
}
/**/
/*
*
* 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 (decrenent internal char counter)
break
else
if(time>timeout) break
}
return(# of chars available)
****END NOTE
*/
grpack(nt3, nt4, len, cnt1)
int *nt3, *nt4, *len;
char cnt1[];
{
unsigned int nt1, check, checkchk, i;
unsigned char c, c2;
int ii;
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;
/*i = grpkt[1] ^ grpkt[2] ^ grpkt[3] ^ grpkt[4] ^ grpkt[5];*/
i = (unsigned)grpkt[1] ^ (unsigned)grpkt[2] ^
(unsigned)grpkt[3] ^ (unsigned)grpkt[4] ^
(unsigned)grpkt[5];
i &= 0xff;
printmsg( 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5],
i
);
if (i) { /* bad header */
printmsg( 0, "****bad header****" );
return(ERROR); /* Im not sure whether "g" considers it an empty or 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); /* cant 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;
/* havnt 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 */
{
}
/*
grdmsg
read a null terminated string
*/
grdmsg( buf )
char * buf;
{
}
/*
gwrdata
read a file and send it out
*/
gwrdata( f )
{
}
/*
grrdata
read in data and send to file
*/
grrdata( f )
{
}
/*
grdblk
read a block of data in
*/
grdblk( blk, len )
{
}
/*
gwrblk
write out a block of data
*/
gwrblk( blk, len )
{
}