/* "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 */ #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 OK -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*/ /******************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=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); 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;i0 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 >= SWINDOW) if(gmachine()!= OK) 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);i2) printmsg("*send %d3) printmsg("Kbytes transfered %d errors %d\r",npkt/KPKT,nerr); if(nerr >= MAXERR) goto close; dflg=0; switch(grpack(&rack,&rseq,&rlen,rdata)) { case CLOSE: if(debug>2) printmsg("**got CLOSE"); goto close; case NAK: nerr++; acktmr=naktmr=0; /* stop ack/nak timer */ if(debug>2) printmsg("**got NAK %d",rack); nloop: if(between(swl,rack,swu)) { /* resend rack->(swu-1) */ i1 = rack; gspack(DATA,rwl,rack,outlen[i1],outbuf[i1]); if(debug>2) printmsg("***resent %d",rack); ftimer[i1]=time(&ttmp); rack=(1+rack)%MAXSEQ; goto nloop; } if(dflg) return(OK); goto reply; /* any other stuff ? */ case EMPTY: if(debug>2) printmsg("**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; if(debug > 2) printmsg("--->seq,elapst %d %ld",i2,(itmp-ftimer[i1])); if((itmp-ftimer[i1]) >= TIMEOUT) { if(debug>2) printmsg("***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(OK); case ACK: if(debug>2) printmsg("**got ACK %d",rack); acktmr=naktmr=0; /* disable ack/nak's */ aloop: if(between(swl,rack,swu)) { /* S<-- -->(S+W-1)%8 */ if(debug>2) printmsg("***ACK %d",swl); ftimer[swl]=0; nbuffers--; swl = (1+swl)%MAXSEQ; goto aloop; } if(dflg) return(OK); /* hack for non-mtask sys's */ /* to empty "inbuf[]" */ goto reply; case DATA: if(debug>2) printmsg("**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; if(debug>2) printmsg("***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++; if(debug>2) printmsg("***unexpect %d ne %d",rseq,rwl);} } else {nerr++; if(debug>2) printmsg("***wrong seq %d",rseq);} goto aloop; case ERROR: nerr++; if(debug>2) printmsg("**got BAD CHK"); gspack(NAK,rwl,0,0,rdata); naktmr=time(&ttmp); /* set nak timer */ if(debug>2) printmsg("***NAK d %d",rwl); goto reply; default: if(debug>2) printmsg("**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 ***/ if(debug > 2) printmsg("send packet type %d, num=%d, n=%d, len=%d",nt2,nt3,nt4,len); if(debug > 3) printmsg("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; /* 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 &= 0xff; if(i) { /* bad header */ if(debug) printmsg("****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) { if(debug>0) printmsg("***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'; } if(debug > 2) printmsg("rec packet type %d, num=%d, n=%d, len=%d",nt1,*nt3,*nt4,*len); if(debug > 3) printmsg(" 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