|
|
1.1 ! root 1: /* C K C F N 2 -- System-independent Kermit protocol support functions... */ ! 2: ! 3: /* ...Part 2 (continued from ckcfns.c) */ ! 4: /* ! 5: Author: Frank da Cruz (SY.FDC@CU20B), ! 6: Columbia University Center for Computing Activities, January 1985. ! 7: Copyright (C) 1985, Trustees of Columbia University in the City of New York. ! 8: Permission is granted to any individual or institution to use, copy, or ! 9: redistribute this software so long as it is not sold for profit, provided this ! 10: copyright notice is retained. ! 11: */ ! 12: /* ! 13: Note -- if you change this file, please amend the version number and date at ! 14: the top of ckcfns.c accordingly. ! 15: */ ! 16: ! 17: #include "ckcker.h" ! 18: #include "ckcdeb.h" ! 19: ! 20: extern int spsiz, rpsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, ! 21: capas; ! 22: extern int pktnum, prvpkt, sndtyp, bctr, bctu, ! 23: size, osize, maxsize, spktl, nfils, stdouf, warn, timef; ! 24: extern int parity, speed, turn, turnch, ! 25: delay, displa, pktlog, tralog, seslog, xflg, mypadn; ! 26: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize; ! 27: extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen; ! 28: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, *hlptxt; ! 29: extern CHAR filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, ! 30: mystch; ! 31: extern char *cmarg, *cmarg2, **cmlist; ! 32: char *strcpy(); ! 33: CHAR dopar(); ! 34: ! 35: /* I N P U T -- Attempt to read packet number 'pktnum'. */ ! 36: ! 37: /* ! 38: This is the function that feeds input to Kermit's finite state machine. ! 39: ! 40: If a special start state is in effect, that state is returned as if it were ! 41: the type of an incoming packet. Otherwise: ! 42: ! 43: . If the desired packet arrives within MAXTRY tries, return its type, ! 44: with its data stored in the global 'data' array. ! 45: ! 46: . If the previous packet arrives again, resend the last packet and wait for ! 47: another to come in. ! 48: ! 49: . If the desired packet does not arrive within MAXTRY tries, return indicating ! 50: that an error packet should be sent. ! 51: */ ! 52: ! 53: input() { ! 54: int len, num, type, numtry; ! 55: ! 56: if (sstate != 0) { /* If a start state is in effect, */ ! 57: type = sstate; /* return it like a packet type, */ ! 58: sstate = 0; /* and then nullify it. */ ! 59: *data = '\0'; ! 60: return(type); ! 61: } else type = rpack(&len,&num,data); /* Else, try to read a packet. */ ! 62: ! 63: /* If it's the same packet we just sent, it's an echo. Read another. */ ! 64: ! 65: if (type == sndtyp) type = rpack(&len,&num,data); ! 66: ! 67: chkint(); /* Check for console interrupts. */ ! 68: /* ! 69: If previous packet again, a timeout pseudopacket, or a bad packet, try again. ! 70: */ ! 71: for (numtry = 0; ! 72: (num == prvpkt || type == 'T' || type == 'Q' || type == 'N'); ! 73: numtry++) { ! 74: if (numtry > MAXTRY) { /* If too many tries, give up */ ! 75: strcpy(data,"Timed out."); /* and send a timeout error packet. */ ! 76: return('E'); ! 77: } ! 78: resend(); /* Else, send last packet again, */ ! 79: if (sstate != 0) { /* If an interrupt routine has set */ ! 80: type = sstate; /* sstate behind our back, return */ ! 81: sstate = 0; /* that. */ ! 82: *data = '\0'; ! 83: return(type); ! 84: } else type = rpack(&len,&num,data); /* Else, try to read a packet. */ ! 85: chkint(); /* Look again for interruptions. */ ! 86: if (type == sndtyp) type = rpack(&len,&num,data); ! 87: } ! 88: ttflui(); /* Got what we want, clear input buffer. */ ! 89: return(type); /* Success, return packet type. */ ! 90: } ! 91: ! 92: /* S P A C K -- Construct and send a packet */ ! 93: ! 94: spack(type,num,len,dat) char type, *dat; int num, len; { ! 95: int i,j; ! 96: ! 97: j = dopar(padch); ! 98: for (i = 0; i < npad; sndpkt[i++] = j) /* Do any requested padding */ ! 99: ; ! 100: sndpkt[i++] = dopar(mystch); /* Start packet with the start char */ ! 101: sndpkt[i++] = dopar(tochar(len+bctu+2)); /* Put in the length */ ! 102: sndpkt[i++] = dopar(tochar(num)); /* The packet number */ ! 103: sndpkt[i++] = dopar(sndtyp = type); /* Packet type */ ! 104: ! 105: for (j = len; j > 0; j-- ) sndpkt[i++] = dopar(*dat++); /* Data */ ! 106: ! 107: sndpkt[i] = '\0'; /* Mark end for block check */ ! 108: switch(bctu) { ! 109: case 1: /* Type 1 - 6 bit checksum */ ! 110: sndpkt[i++] = dopar(tochar(chk1(sndpkt+1))); ! 111: break; ! 112: case 2: /* Type 2 - 12 bit checksum*/ ! 113: j = chk2(sndpkt+1); ! 114: sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); ! 115: sndpkt[i++] = dopar(tochar(j & 077)); ! 116: break; ! 117: case 3: /* Type 3 - 16 bit CRC-CCITT */ ! 118: j = chk3(sndpkt+1); ! 119: sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12)); ! 120: sndpkt[i++] = dopar(tochar((j & 07700) >> 6)); ! 121: sndpkt[i++] = dopar(tochar(j & 077)); ! 122: break; ! 123: } ! 124: for (j = npad; j > 0; j-- ) sndpkt[i++] = dopar(padch); /* Padding */ ! 125: ! 126: sndpkt[i++] = dopar(seol); /* EOL character */ ! 127: sndpkt[i] = '\0'; /* End of the packet */ ! 128: ttol(sndpkt,spktl=i); /* Send the packet just built */ ! 129: flco += spktl; /* Count the characters */ ! 130: tlco += spktl; ! 131: if (pktlog) zsoutl(ZPFILE,sndpkt); /* If logging packets, log it */ ! 132: screen(SCR_PT,type,(long)num,sndpkt); /* Update screen */ ! 133: } ! 134: ! 135: /* D O P A R -- Add an appropriate parity bit to a character */ ! 136: ! 137: CHAR ! 138: dopar(ch) char ch; { ! 139: int a, b; ! 140: if (!parity) return(ch); else ch &= 0177; ! 141: switch (parity) { ! 142: case 'm': return(ch | 128); /* Mark */ ! 143: case 's': return(ch & 127); /* Space */ ! 144: case 'o': /* Odd (fall thru) */ ! 145: case 'e': /* Even */ ! 146: a = (ch & 15) ^ ((ch >> 4) & 15); ! 147: a = (a & 3) ^ ((a >> 2) & 3); ! 148: a = (a & 1) ^ ((a >> 1) & 1); ! 149: if (parity == 'o') a = 1 - a; /* Switch sense for odd */ ! 150: return(ch | (a << 7)); ! 151: default: return(ch); ! 152: } ! 153: } ! 154: ! 155: /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ ! 156: ! 157: chk1(pkt) char *pkt; { ! 158: int chk; ! 159: chk = chk2(pkt); ! 160: return((((chk & 0300) >> 6) + chk) & 077); ! 161: } ! 162: ! 163: ! 164: /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ ! 165: ! 166: chk2(pkt) char *pkt; { ! 167: unsigned int chk; ! 168: int p; ! 169: for (chk = 0; *pkt != '\0'; *pkt++) { ! 170: p = (parity) ? *pkt & 0177 : *pkt; ! 171: chk += p; ! 172: } ! 173: return(chk); ! 174: } ! 175: ! 176: ! 177: /* C H K 3 -- Compute a type-3 Kermit block check. */ ! 178: /* ! 179: Calculate the 16-bit CRC of a null-terminated string using a byte-oriented ! 180: tableless algorithm invented by Andy Lowry (Columbia University). The ! 181: magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1. ! 182: Note - this function could be adapted for strings containing imbedded 0's ! 183: by including a length argument. ! 184: */ ! 185: chk3(s) char *s; { ! 186: unsigned int c, q; ! 187: LONG crc = 0; ! 188: ! 189: while ((c = *s++) != '\0') { ! 190: if (parity) c &= 0177; ! 191: q = (crc ^ c) & 017; /* Low-order nibble */ ! 192: crc = (crc >> 4) ^ (q * 010201); ! 193: q = (crc ^ (c >> 4)) & 017; /* High order nibble */ ! 194: crc = (crc >> 4) ^ (q * 010201); ! 195: } ! 196: return(crc); ! 197: } ! 198: ! 199: /* Functions for sending various kinds of packets */ ! 200: ! 201: ack() { /* Send an ordinary acknowledgment. */ ! 202: spack('Y',pktnum,0,""); /* No data. */ ! 203: nxtpkt(&pktnum); /* Increment the packet number. */ ! 204: } /* Note, only call this once! */ ! 205: ! 206: ack1(s) char *s; { /* Send an ACK with data. */ ! 207: spack('Y',pktnum,strlen(s),s); /* Send the packet. */ ! 208: nxtpkt(&pktnum); /* Increment the packet number. */ ! 209: } /* Only call this once! */ ! 210: ! 211: nack() { /* Negative acknowledgment. */ ! 212: spack('N',pktnum,0,""); /* NAK's never have data. */ ! 213: } ! 214: ! 215: resend() { /* Send the old packet again. */ ! 216: int w; ! 217: ! 218: for (w = 0; w < timint - 2; w++) { /* Be extra sure no stuff is */ ! 219: ttflui(); /* still coming in. */ ! 220: sleep(1); ! 221: if (!ttchk() ) ttinc(1); /* be extra sure no stuff in SIII/V */ ! 222: if (!ttchk() ) break; ! 223: } ! 224: if (*sndpkt) ttol(sndpkt,spktl); /* Resend if buffer not empty */ ! 225: screen(SCR_PT,'%',(long)pktnum,sndpkt); /* Display that resend occurred */ ! 226: if (pktlog && *sndpkt) zsoutl(ZPFILE,sndpkt); /* Log packet if desired */ ! 227: } ! 228: ! 229: errpkt(reason) char *reason; { /* Send an error packet. */ ! 230: encstr(reason); ! 231: spack('E',pktnum,size,data); ! 232: screen(SCR_TC,0,0l,""); ! 233: } ! 234: ! 235: scmd(t,dat) char t, *dat; { /* Send a packet of the given type */ ! 236: encstr(dat); /* Encode the command string */ ! 237: spack(t,pktnum,size,data); ! 238: } ! 239: ! 240: srinit() { /* Send R (GET) packet */ ! 241: encstr(cmarg); /* Encode the filename. */ ! 242: spack('R',pktnum,size,data); /* Send the packet. */ ! 243: } ! 244: ! 245: nxtpkt(num) int *num; { ! 246: prvpkt = *num; /* Save previous */ ! 247: *num = (*num + 1) % 64; /* Increment packet number mod 64 */ ! 248: } ! 249: ! 250: sigint() { /* Terminal interrupt handler */ ! 251: errpkt("User typed ^C"); ! 252: doexit(GOOD_EXIT); /* Exit program */ ! 253: } ! 254: ! 255: /* R P A C K -- Read a Packet */ ! 256: ! 257: rpack(l,n,dat) int *l, *n; char *dat; { ! 258: int i, j, x, done, pstart, pbl, cccount, tries, gotsoh; ! 259: CHAR chk[4], xchk[4], t, type; ! 260: ! 261: /* Try 3 times to get a line that has a start-of-packet char in it. */ ! 262: /* This allows skipping of blank lines that some hosts might send. */ ! 263: ! 264: for (gotsoh = tries = 0; (tries < 3) && (gotsoh == 0); tries++) { ! 265: j = inlin(); /* Read a line */ ! 266: if (j < 0) { ! 267: debug(F101,"rpack: inlin fails","",j); ! 268: screen(SCR_PT,'T',(long)pktnum,""); ! 269: return('T'); ! 270: } ! 271: debug(F111,"rpack: inlin ok, recpkt",recpkt,j); ! 272: for (i = 0; ((t = recpkt[i]) != stchr) && (i < j); i++) ! 273: ; /* Look for start of packet char */ ! 274: gotsoh = (t == stchr); ! 275: } ! 276: if (gotsoh) i++; else return('Q'); /* No SOH in 3 tries, fail. */ ! 277: ! 278: /* Got something that starts out like a packet, now "parse" it. */ ! 279: ! 280: debug(F101,"entering rpack with i","",i); ! 281: done = 0; ! 282: while (!done) { ! 283: debug(F101,"rpack starting at i","",i); ! 284: pstart = i; /* remember where packet started */ ! 285: ! 286: /* length */ ! 287: ! 288: if ((t = recpkt[i++]) == stchr) continue; /* Resynch if SOH */ ! 289: ! 290: if (t == 3) cccount++; /* Count any control-C's */ ! 291: ! 292: if (t == eol) return('Q'); ! 293: *l = unchar(t); /* Packet length */ ! 294: debug(F101," pkt len","",*l); ! 295: ! 296: /* sequence number */ ! 297: ! 298: if ((t = recpkt[i++]) == stchr) continue; ! 299: if (cccount && (t == 3)) { conoll("^C^C exit..."); doexit(0); } ! 300: if (t == eol) return('Q'); ! 301: *n = unchar(t); ! 302: debug(F101,"rpack: n","",*n); ! 303: ! 304: /* cont'd... */ ! 305: ! 306: /* ...rpack(), cont'd */ ! 307: ! 308: ! 309: /* type */ ! 310: ! 311: if ((type = recpkt[i++]) == stchr) continue; ! 312: if (type == eol) return('Q'); ! 313: debug(F101,"rpack: type","",type); ! 314: ! 315: if ((type == 'S') || (type == 'I')) pbl = 1; /* Heuristics for */ ! 316: else if (type == 'N') pbl = *l - 2; /* syncing block check type */ ! 317: else pbl = bctu; ! 318: ! 319: *l -= (pbl + 2); /* Now compute data length */ ! 320: debug(F101,"rpack: bctu","",bctu); ! 321: debug(F101," pbl","",pbl); ! 322: debug(F101," data length","",*l); ! 323: ! 324: /* data */ ! 325: ! 326: dat[0] = '\0'; /* Return null string if no data */ ! 327: for (j=0; j<*l; i++,j++) ! 328: if ((dat[j] = recpkt[i]) == stchr) continue; ! 329: else if (dat[j] == eol) return('Q'); ! 330: dat[j] = '\0'; ! 331: ! 332: /* get the block check */ ! 333: ! 334: debug(F110," packet chk",recpkt+i,0); ! 335: for (j = 0; j < pbl; j++) { ! 336: chk[j] = recpkt[i]; ! 337: debug(F101," chk[j]","",chk[j]); ! 338: if (chk[j] == stchr) break; ! 339: if (chk[j] == eol) return('Q'); ! 340: recpkt[i++] = '\0'; ! 341: } ! 342: chk[j] = 0; ! 343: debug(F111," chk array, j",chk,j); ! 344: if (j != pbl) continue; /* Block check right length? */ ! 345: done = 1; /* Yes, done. */ ! 346: } ! 347: ! 348: /* cont'd... */ ! 349: ! 350: /* ...rpack(), cont'd */ ! 351: ! 352: ! 353: /* Got packet, now check the block check */ ! 354: ! 355: switch (pbl) { ! 356: case 1: ! 357: xchk[0] = tochar(chk1(&recpkt[pstart])); ! 358: if (chk[0] != xchk[0]) { ! 359: if (deblog) { ! 360: debug(F000,"rpack: chk","",chk[0]); ! 361: debug(F000," should be ","",xchk[0]); ! 362: } ! 363: screen(SCR_PT,'Q',(long)n,recpkt); ! 364: return('Q'); ! 365: } ! 366: break; ! 367: case 2: ! 368: x = chk2(&recpkt[pstart]); ! 369: xchk[0] = tochar((x & 07700) >> 6); ! 370: xchk[1] = tochar(x & 077); ! 371: if (deblog) { ! 372: debug(F000," xchk[0]","=",xchk[0]); ! 373: debug(F000," xchk[1]","=",xchk[1]); ! 374: } ! 375: if ((xchk[0] != chk[0]) || (xchk[1] != chk[1])) { ! 376: debug(F100," bct2's don't compare","",0); ! 377: screen(SCR_PT,'Q',(long)n,recpkt); ! 378: return('Q'); ! 379: } ! 380: break; ! 381: case 3: ! 382: x = chk3(&recpkt[pstart]); ! 383: xchk[0] = tochar(( (unsigned)(x & 0170000)) >> 12); ! 384: xchk[1] = tochar((x & 07700) >> 6); ! 385: xchk[2] = tochar(x & 077); ! 386: if (deblog) { ! 387: debug(F000," xchk[0]","=",xchk[0]); ! 388: debug(F000," xchk[1]","=",xchk[1]); ! 389: debug(F000," xchk[2]","=",xchk[2]); ! 390: } ! 391: if ((xchk[0] != chk[0]) || ! 392: (xchk[1] != chk[1]) || ! 393: (xchk[2] != chk[2])) { ! 394: debug(F100," bct3's don't compare","",0); ! 395: screen(SCR_PT,'Q',(long)n,recpkt); ! 396: return('Q'); ! 397: } ! 398: break; ! 399: } ! 400: ! 401: /* Good packet, return its type */ ! 402: ! 403: screen(SCR_PT,type,(long)(*n),recpkt); /* Update screen */ ! 404: return(type); ! 405: } ! 406: ! 407: /* I N C H R -- Input character from communication line, with timeout */ ! 408: ! 409: inchr(timo) int timo; { ! 410: int c; ! 411: c = ttinc(timo); ! 412: debug(F101,"inchr ttinc","",c); ! 413: if (c < 0) return(c); /* Get a character */ ! 414: if (parity) c = c & 0177; /* If parity on, discard parity bit. */ ! 415: debug(F101," after parity","",c); ! 416: return(c); ! 417: } ! 418: ! 419: ! 420: /* I N L I N -- Input a line (up to break char) from communication line */ ! 421: ! 422: /* Returns number of chars input on success, -1 on failure. */ ! 423: /* Number of chars guaranteed to be within RBUFL. */ ! 424: ! 425: inlin() { ! 426: int i, j, k, maxt; ! 427: CHAR e; ! 428: ! 429: maxt = (speed >= 110) ? (MAXTRY * 9600 / speed) : MAXTRY; ! 430: debug(F101,"inlin: speed","",speed); ! 431: debug(F101," maxt","",maxt); ! 432: e = (turn) ? turnch : eol; ! 433: i = j = k = 0; ! 434: if (parity) { ! 435: while ((j != e) && (i < RBUFL) && (k < maxt)) { ! 436: j = inchr(1); /* Get char, 1 second timeout */ ! 437: debug(F101,"inlin inchr","",j); ! 438: if (j < 0) k++; /* Timed out, count. */ ! 439: else { ! 440: if (j) recpkt[i++] = j; /* Got one, save it, */ ! 441: k = 0; /* and reset timeout counter. */ ! 442: } ! 443: } ! 444: } else { ! 445: i = ttinl(recpkt,RBUFL,timint,e); /* Get them all at once */ ! 446: if (i < 0) k = 1; ! 447: } ! 448: recpkt[i+1] = '\0'; /* Terminate near end of packet */ ! 449: debug(F111,"inlin",recpkt,i); /* Debug report... */ ! 450: debug(F101," timeouts","",k); ! 451: if (i < 1) return(-1); /* No characters, return. */ ! 452: if (pktlog) zsoutl(ZPFILE,recpkt); /* Log any we got, if logging. */ ! 453: if (k > maxt) return(-1); /* If too many tries, give up. */ ! 454: tlci += i; /* All OK, Count the characters. */ ! 455: flci += i; ! 456: return(i); ! 457: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.