/* C K F N S 2 -- System-independent Kermit protocol support functions... */ /* modified for CTOS C2.0 by Joel Dunn, UNC-CH, October 1986 */ /* modified May 1992 by Doug Drury ITT-Federal Services */ /* changed inlin() k < to k <= to enable timeouts */ /* changed inlin () MAXTRY to timint at line 426 */ /* changed MAXTRY to maxtry to implement variable retry limit */ /* removed timing loop around flush of incoming characters so none lost */ /* ...Part 2 (continued from ckfns.c) */ /* Note -- if you change this file, please amend the version number and date at the top of ckfns.c accordingly. */ #include "ctermi.h" extern int spsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas; extern int pktnum, prvpkt, sndtyp, fsize, bctr, bctu, maxtry, size, osize, maxsize, spktl, nfils, stdouf, warn, timef; extern int parity, speed, turn, turnch, delaytime, displa, pktlog, tralog, seslog, xflg, mypadn; extern long filcnt, ffc, flci, flco, tlci, tlco, tfc; extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen; extern char padch, mypadc, eol, reol, ctlq, myctlq, sstate, *hlptxt; extern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, mystch; extern char *cmarg, *cmarg2, **cmlist; char *strcpy(); /* I N P U T -- Attempt to read packet number 'pktnum'. */ /* This is the function that feeds input to Kermit's finite state machine. If a special start state is in effect, that state is returned as if it were the type of an incoming packet. Otherwise: . If the desired packet arrives within MAXTRY tries, return its type, with its data stored in the global 'data' array. . If the previous packet arrives again, resend the last packet and wait for another to come in. . If the desired packet does not arrive within MAXTRY tries, return indicating that an error packet should be sent. */ input() { int len, num, type, numtry; if (sstate != 0) { /* If a start state is in effect, */ type = sstate; /* return it like a packet type, */ sstate = 0; /* and then nullify it. */ *data = '\0'; return(type); } else type = rpack(&len,&num,data); /* Else, try to read a packet. */ /* If it's the same packet we just sent, it's an echo. Read another. */ if (type == sndtyp) type = rpack(&len,&num,data); chkint(); /* Check for console interrupts. */ /* If previous packet again, a timeout pseudopacket, or a bad packet, try again. */ for (numtry = 0; num == prvpkt || type == 'N' || type == 'T' || type == 'Q' ; numtry++) { if (numtry >= maxtry) { /* If too many tries, give up */ strcpy(data,"Timed out."); /* and send a timeout error packet. */ return('E'); } resend(); /* Else, send last packet again, */ type = rpack(&len,&num,data); /* and try to read a new one. */ chkint(); /* Look again for interruptions. */ } return(type); /* Success, return packet type. */ } /* S P A C K -- Construct and send a packet */ spack(type,num,len,dat) char type, *dat; int num, len; { int i,j; j = dopar(padch); for (i = 0; i < npad; sndpkt[i++] = j) /* Do any requested padding */ ; sndpkt[i++] = dopar(mystch); /* Start packet with the start char */ sndpkt[i++] = dopar(tochar(len+bctu+2)); /* Put in the length */ sndpkt[i++] = dopar(tochar(num)); /* The packet number */ sndpkt[i++] = sndtyp = dopar(type); /* Packet type */ for (j = len; j > 0; j-- ) sndpkt[i++] = dopar(*dat++); /* Data */ sndpkt[i] = '\0'; /* Mark end for block check */ switch(bctu) { case 1: /* Type 1 - 6 bit checksum */ sndpkt[i++] = dopar(tochar(chk1(sndpkt+1))); break; case 2: /* Type 2 - 12 bit checksum*/ j = chk2(sndpkt+1); sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); sndpkt[i++] = dopar(tochar(j & 077)); break; case 3: /* Type 3 - 16 bit CRC-CCITT */ j = chk3(sndpkt+1); sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12)); sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); sndpkt[i++] = dopar(tochar(j & 077)); break; } for (j = npad; j > 0; j-- ) sndpkt[i++] = dopar(padch); /* Padding */ sndpkt[i++] = dopar(eol); /* EOL character */ sndpkt[i] = '\0'; /* End of the packet */ ttol(sndpkt,spktl=i); /* Send the packet just built */ flco += spktl; /* Count the characters */ tlco += spktl; if (pktlog) zsoutl(ZPFILE,sndpkt); /* If logging packets, log it */ screen(type,(long)num,sndpkt); /* Update screen */ } /* D O P A R -- Add an appropriate parity bit to a character */ dopar (ch) char ch; { int a; switch (parity) { case 'm': return(ch | 128); /* Mark */ case 's': return(ch & 127); /* Space */ case 'o': ch |= 128; /* Odd (fall thru) */ case 'e': /* Even */ a = (ch & 15) ^ ((ch >> 4) & 15); a = (a & 3) ^ ((a >> 2) & 3); a = (a & 1) ^ ((a >> 1) & 1); return(ch | (a << 7)); default: return(ch); } } /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ chk1(pkt) char *pkt; { int chk; chk = chk2(pkt); return((((chk & 0300) >> 6) + chk) & 077); } /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ /* CTOS C1.0 barfed at original contents, hence changes to code to simplify the expressions 'till it worked - now on C2.0, leave sleeping dogs alone */ chk2(pkt) char *pkt; { unsigned int chk; int p; chk = 0; while (*pkt != '\0') { if (parity) p = *pkt & 0177; else p = *pkt; chk += p; pkt++; } return(chk); } /* C H K 3 -- Compute a type-3 Kermit block check. */ /* Calculate the 16-bit CRC of a null-terminated string using a byte-oriented tableless algorithm invented by Andy Lowry (Columbia University). The magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1. Note - this function could adapted for strings containing imbedded 0's by including a length argument. */ chk3(s) char *s; { unsigned int c, q; LONG crc = 0; while ((c = *s++) != '\0') { if (parity) c &= 0177; q = (crc ^ c) & 017; /* Low-order nibble */ crc = (crc >> 4) ^ (q * 010201); q = (crc ^ (c >> 4)) & 017; /* High order nibble */ crc = (crc >> 4) ^ (q * 010201); } return(crc); } /* Functions for sending various kinds of packets */ ack() { /* Send an ordinary acknowledgment. */ spack('Y',pktnum,0,""); /* No data. */ nxtpkt(&pktnum); /* Increment the packet number. */ } /* Note, only call this once! */ ack1(s) char *s; { /* Send an ACK with data. */ spack('Y',pktnum,strlen(s),s); /* Send the packet. */ nxtpkt(&pktnum); /* Increment the packet number. */ } /* Only call this once! */ nack() { /* Negative acknowledgment. */ spack('N',pktnum,0,""); /* NAK's never have data. */ } resend() { /* Send the old packet again. */ int w; /* for (w = 0; w < timint - 2; w++) { be extra sure no stuff is */ ttflui(); /* still comming in */ /* delay(5); } */ ttol(sndpkt,spktl); screen('%',(long)pktnum,sndpkt); if (pktlog) zsoutl(ZPFILE,sndpkt); } errpkt(reason) char *reason; { /* Send an error packet. */ encstr(reason); spack('E',pktnum,size,data); } scmd(t,dat) char t, *dat; { /* Send a packet of the given type */ encstr(dat); /* Encode the command string */ ttflui(); /* Flush pending input. */ spack(t,pktnum,size,data); } srinit() { /* Send R (GET) packet */ encstr(cmarg); /* Encode the filename. */ ttflui(); /* Flush pending input. */ spack('R',pktnum,size,data); /* Send the packet. */ } nxtpkt(num) int *num; { prvpkt = *num; /* Save previous */ *num = (*num + 1) % 64; /* Increment packet number mod 64 */ } sigint() { /* Terminal interrupt handler */ errpkt("User typed ^C"); doexit(0); /* Exit with status = 0 */ } /* R P A C K -- Read a Packet */ rpack(l,n,dat) int *l, *n; char *dat; { int i, j, x, done, pstart, pbl; char chk[4], xchk[4], t, type; chk[3] = xchk[3] = 0; i = inlin(); /* Read a line */ if (i != 0) { debug(F101,"rpack: inlin","",i); screen('T',(long)pktnum,""); return('T'); } debug(F110,"rpack: inlin ok, recpkt",recpkt,0); /* Look for start of packet */ for (i = 0; ((t = recpkt[i]) != stchr) && (i < RBUFL) ; i++) ; if (++i >= RBUFL) return('Q'); /* Skip rest if not found */ /* now "parse" the packet */ debug(F101,"entering rpack with i","",i); done = 0; while (!done) { debug(F101,"rpack starting at i","",i); pstart = i; /* remember where packet started */ /* length */ if ((t = recpkt[i++]) == stchr) continue; /* Resynch if SOH */ /*** if (t == 2) doexit(0); *** uncomment this to allow ^A^B cause exit ***/ if (t == reol) return('Q'); *l = unchar(t); /* Packet length */ debug(F101," pkt len","",*l); /* sequence number */ if ((t = recpkt[i++]) == stchr) continue; if (t == reol) return('Q'); *n = unchar(t); debug(F101,"rpack: n","",*n); /* cont'd... */ /* ...rpack(), cont'd */ /* type */ if ((type = recpkt[i++]) == stchr) continue; if (type == reol) return('Q'); debug(F101,"rpack: type","",type); if ((type == 'S') || (type == 'I')) pbl = 1; /* Heuristics for */ else if (type == 'N') pbl = *l - 2; /* syncing block check type */ else pbl = bctu; *l -= (pbl + 2); /* Now compute data length */ debug(F101,"rpack: bctu","",bctu); debug(F101," pbl","",pbl); debug(F101," data length","",*l); /* data */ dat[0] = '\0'; /* Return null string if no data */ for (j=0; j<*l; i++,j++) if ((dat[j] = recpkt[i]) == stchr) continue; else if (dat[j] == reol) return('Q'); dat[j] = '\0'; /* get the block check */ debug(F110," packet chk",recpkt+i,0); for (j = 0; j < pbl; j++) { chk[j] = recpkt[i]; debug(F101," chk[j]","",chk[j]); if (chk[j] == stchr) break; if (chk[j] == eol) return('Q'); recpkt[i++] = '\0'; } chk[j] = 0; debug(F111," chk array, j",chk,j); if (j != pbl) continue; /* Block check right length? */ done = 1; /* Yes, done. */ } /* cont'd... */ /* ...rpack(), cont'd */ /* Got packet, now check the block check */ switch (pbl) { case 1: xchk[0] = tochar(chk1(&recpkt[pstart])); if (chk[0] != xchk[0]) { if (deblog) { debug(F000,"rpack: chk","",chk[0]); debug(F000," should be ","",xchk[0]); } screen('Q',(long)n,recpkt); return('Q'); } break; case 2: x = chk2(&recpkt[pstart]); xchk[0] = tochar((x & 07700) >> 6); xchk[1] = tochar(x & 077); if (deblog) { debug(F000," xchk[0]","=",xchk[0]); debug(F000," xchk[1]","=",xchk[1]); } if ((xchk[0] != chk[0]) || (xchk[1] != chk[1])) { debug(F100," bct2's don't compare","",0); screen('Q',(long)n,recpkt); return('Q'); } break; case 3: x = chk3(&recpkt[pstart]); xchk[0] = tochar(( (unsigned)(x & 0170000)) >> 12); xchk[1] = tochar((x & 07700) >> 6); xchk[2] = tochar(x & 077); if (deblog) { debug(F000," xchk[0]","=",xchk[0]); debug(F000," xchk[1]","=",xchk[1]); debug(F000," xchk[2]","=",xchk[2]); } if ((xchk[0] != chk[0]) || (xchk[1] != chk[1]) || (xchk[2] != chk[2])) { debug(F100," bct3's don't compare","",0); screen('Q',(long)n,recpkt); return('Q'); } break; } /* Good packet, return its type */ ttflui(); /* Done, flush any remaining. */ screen(_tolower(type),(long)(*n),recpkt); /* Update screen */ return(type); } /* I N C H R -- Input character from communication line, with timeout */ inchr(timo) int timo; { int c; c = ttinc(timo); debug(F101,"inchr ttinc","",c); if (c < 0) return(c); /* Get a character */ if (parity) c = c & 0177; /* If parity on, discard parity bit. */ debug(F101," after parity","",c); return(c); } /* I N L I N -- Input a line (up to break char) from communication line */ /* Returns 0 on success, nonzero on failure */ inlin() { int e, i, j, k; e = (turn) ? turnch : reol; i = j = k = 0; if (parity) { while ((j != e) && (i < RBUFL) && (k <= timint)) { j = inchr(1); /* Get char, 1 second timeout */ debug(F101,"inlin inchr","",j); if (j < 0) k++; /* Timed out. */ else { if (j) recpkt[i++] = j; /* Save it */ k = 0; /* Reset timeout counter. */ } } } else { i = ttinl(recpkt,RBUFL,timint,e); /* Get them all at once */ if (i < 0) k = 1; } debug(F111,"inlin",recpkt,i); debug(F101," timeouts","",k); if (i < 1) return(1); if (pktlog) zsoutl(ZPFILE,recpkt); if (k > maxtry) return(1); tlci += i; /* Count the characters. */ flci += i; recpkt[i+1] = '\0'; /* Terminate the input string. */ return(0); }