|
|
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: Modified July 87 to incorporate changes from Jim Noble of ! 6: Planning Research Corp for Macintosh Megamax C support. ! 7: */ ! 8: /* ! 9: Author: Frank da Cruz (SY.FDC@CU20B), ! 10: Columbia University Center for Computing Activities, January 1985. ! 11: Copyright (C) 1985, Trustees of Columbia University in the City of New York. ! 12: Permission is granted to any individual or institution to use, copy, or ! 13: redistribute this software so long as it is not sold for profit, provided this ! 14: copyright notice is retained. ! 15: */ ! 16: /* ! 17: Note -- if you change this file, please amend the version number and date at ! 18: the top of ckcfns.c accordingly. ! 19: */ ! 20: ! 21: #include "ckcsym.h" /* Conditional compilation (for Macintosh) */ ! 22: #include "ckcker.h" ! 23: #include "ckcdeb.h" ! 24: ! 25: extern int spsiz, rpsiz, timint, npad, ebq, ebqflg, rpt, rptq, rptflg, capas; ! 26: extern int pktnum, prvpkt, sndtyp, bctr, bctu, rsn, rln, maxtry, size; ! 27: extern int osize, maxsize, spktl, nfils, stdouf, warn, timef, parity, speed; ! 28: extern int turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn; ! 29: extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen; ! 30: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize; ! 31: extern char *cmarg, *cmarg2, **cmlist; ! 32: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, *hlptxt; ! 33: extern CHAR filnam[], sndpkt[], recpkt[], data[], srvcmd[]; ! 34: extern CHAR *srvptr, stchr, mystch, *rdatap; ! 35: ! 36: char *strcpy(); /* Forward declarations */ ! 37: unsigned chk2(); /* of non-int functions */ ! 38: CHAR dopar(); /* ... */ ! 39: ! 40: static CHAR partab[] = { /* Even parity table for dopar() */ ! 41: ! 42: '\000', '\201', '\202', '\003', '\204', '\005', '\006', '\207', ! 43: '\210', '\011', '\012', '\213', '\014', '\215', '\216', '\017', ! 44: '\220', '\021', '\022', '\223', '\024', '\225', '\226', '\027', ! 45: '\030', '\231', '\232', '\033', '\234', '\035', '\036', '\237', ! 46: '\240', '\041', '\042', '\243', '\044', '\245', '\246', '\047', ! 47: '\050', '\251', '\252', '\053', '\254', '\055', '\056', '\257', ! 48: '\060', '\261', '\262', '\063', '\264', '\065', '\066', '\267', ! 49: '\270', '\071', '\072', '\273', '\074', '\275', '\276', '\077', ! 50: '\300', '\101', '\102', '\303', '\104', '\305', '\306', '\107', ! 51: '\110', '\311', '\312', '\113', '\314', '\115', '\116', '\317', ! 52: '\120', '\321', '\322', '\123', '\324', '\125', '\126', '\327', ! 53: '\330', '\131', '\132', '\333', '\134', '\335', '\336', '\137', ! 54: '\140', '\341', '\342', '\143', '\344', '\145', '\146', '\347', ! 55: '\350', '\151', '\152', '\353', '\154', '\355', '\356', '\157', ! 56: '\360', '\161', '\162', '\363', '\164', '\365', '\366', '\167', ! 57: '\170', '\371', '\372', '\173', '\374', '\175', '\176', '\377' ! 58: }; ! 59: ! 60: /* I N P U T -- Attempt to read packet number 'pktnum'. */ ! 61: ! 62: /* ! 63: This is the function that feeds input to Kermit's finite state machine. ! 64: ! 65: If a special start state is in effect, that state is returned as if it were ! 66: the type of an incoming packet. Otherwise: ! 67: ! 68: . If the desired packet arrives within MAXTRY tries, return its type, ! 69: with its data stored in the global 'data' array. ! 70: ! 71: . If the previous packet arrives again, resend the last packet and wait for ! 72: another to come in. ! 73: ! 74: . If the desired packet does not arrive within MAXTRY tries, return indicating ! 75: that an error packet should be sent. ! 76: */ ! 77: ! 78: input() { ! 79: int type, numtry; ! 80: ! 81: if (sstate != 0) { /* If a start state is in effect, */ ! 82: type = sstate; /* return it like a packet type, */ ! 83: sstate = 0; /* and then nullify it. */ ! 84: return(type); ! 85: } else type = rpack(); /* Else, try to read a packet. */ ! 86: ! 87: debug(F111,"input",rdatap,type); ! 88: ! 89: /* If it's the same packet we just sent, it's an echo. Read another. */ ! 90: ! 91: if (type == sndtyp) type = rpack(); ! 92: ! 93: chkint(); /* Check for console interrupts. */ ! 94: /* ! 95: If previous packet again, a timeout pseudopacket, or a bad packet, try again. ! 96: */ ! 97: for (numtry = 0; ! 98: (rsn == prvpkt || type == 'T' || type == 'Q' || type == 'N'); ! 99: numtry++) { ! 100: if (numtry > maxtry) { /* If too many tries, give up */ ! 101: strcpy(data,"Timed out."); /* and send a timeout error packet, */ ! 102: rdatap = data; /* and pretend we read one. */ ! 103: return('E'); ! 104: } ! 105: if (type == 'E') return('E'); /* Don't even bother about seq no */ ! 106: if ((type == 'N') && (rsn == ((pktnum+1) & 63))) { ! 107: /* NAK for next packet */ ! 108: return('Y'); /* is ACK for current. */ ! 109: } else { ! 110: resend(); /* Else, send last packet again, */ ! 111: } ! 112: if (sstate != 0) { /* If an interrupt routine has set */ ! 113: type = sstate; /* sstate behind our back, return */ ! 114: sstate = 0; /* that. */ ! 115: *data = '\0'; ! 116: return(type); ! 117: } else type = rpack(); /* Else try to read a packet. */ ! 118: chkint(); /* Look again for interruptions. */ ! 119: if (type == sndtyp) type = rpack(); ! 120: } ! 121: ttflui(); /* Got what we want, clear input buffer. */ ! 122: return(type); /* Success, return packet type. */ ! 123: } ! 124: ! 125: ! 126: /* S P A C K -- Construct and send a packet */ ! 127: ! 128: /* ! 129: spack() sends a packet of the given type, sequence number n, with len ! 130: data characters pointed to by d, in either a regular or extended- ! 131: length packet, depending on length. Returns the number of bytes ! 132: actually sent, or else -1 upon failure. Uses global npad, padch, ! 133: mystch, bctu. Leaves packet in null-terminated global sndpkt[] array for ! 134: later retransmission. Updates global sndpktl (send-packet length). ! 135: */ ! 136: ! 137: spack(type,n,len,d) char type, *d; int n, len; { ! 138: int i, j, lp; CHAR *sohp = sndpkt; CHAR pc; ! 139: ! 140: spktl = 0; ! 141: pc = dopar(padch); /* The pad character, if any. */ ! 142: for (i = 0; i < npad; sndpkt[i++] = pc) /* Do any requested padding */ ! 143: sohp++; ! 144: sndpkt[i++] = dopar(mystch); /* MARK */ ! 145: lp = i++; /* Position of LEN, fill in later */ ! 146: sndpkt[i++] = dopar(tochar(n)); /* SEQ field */ ! 147: sndpkt[i++] = dopar(sndtyp = type); /* TYPE field */ ! 148: j = len + bctu; /* True length */ ! 149: if (j > 95) { /* Long packet? */ ! 150: sndpkt[lp] = dopar(tochar(0)); /* Set LEN to zero */ ! 151: sndpkt[i++] = dopar(tochar(j / 95)); /* High part */ ! 152: sndpkt[i++] = dopar(tochar(j % 95)); /* Low part */ ! 153: sndpkt[i] = '\0'; /* Header checksum */ ! 154: sndpkt[i++] = dopar(tochar(chk1(sndpkt+lp))); ! 155: } else sndpkt[lp] = dopar(tochar(j+2)); /* Normal LEN */ ! 156: ! 157: while (len-- > 0) sndpkt[i++] = dopar(*d++); /* Packet data */ ! 158: sndpkt[i] = '\0'; /* Null-terminate */ ! 159: ! 160: switch (bctu) { /* Block check */ ! 161: case 1: /* 1 = 6-bit chksum */ ! 162: sndpkt[i++] = dopar(tochar(chk1(sndpkt+lp))); ! 163: break; ! 164: case 2: /* 2 = 12-bit chksum */ ! 165: j = chk2(sndpkt+lp); ! 166: sndpkt[i++] = dopar( (unsigned) tochar((j >> 6) & 077)); ! 167: sndpkt[i++] = dopar( (unsigned) tochar(j & 077)); ! 168: break; ! 169: case 3: /* 3 = 16-bit CRC */ ! 170: j = chk3(sndpkt+lp); ! 171: sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12)); ! 172: sndpkt[i++] = dopar(tochar((j >> 6) & 077)); ! 173: sndpkt[i++] = dopar(tochar(j & 077)); ! 174: break; ! 175: } ! 176: sndpkt[i++] = dopar(seol); /* End of line (packet terminator) */ ! 177: sndpkt[i] = '\0'; /* Terminate string */ ! 178: if (ttol(sndpkt,i) < 0) return(-1); /* Send the packet */ ! 179: spktl = i; /* Remember packet length */ ! 180: flco += spktl; /* Count the characters */ ! 181: tlco += spktl; ! 182: if (pktlog) { /* If logging packets, log it */ ! 183: zsout(ZPFILE,"s-"); ! 184: if (*sndpkt) zsoutl(ZPFILE,sndpkt); else zsoutl(ZPFILE,sohp); ! 185: } ! 186: screen(SCR_PT,type,(long)n,sohp); /* Update screen */ ! 187: return(i); /* Return length */ ! 188: } ! 189: ! 190: /* D O P A R -- Add an appropriate parity bit to a character */ ! 191: ! 192: CHAR ! 193: dopar(ch) CHAR ch; { ! 194: int a; ! 195: if (!parity) return(ch & 255); else a = ch & 127; ! 196: switch (parity) { ! 197: case 'e': return(partab[a]) & 255; /* Even */ ! 198: case 'm': return(a | 128); /* Mark */ ! 199: case 'o': return(partab[a] ^ 128) & 255; /* Odd */ ! 200: case 's': return(a & 127); /* Space */ ! 201: default: return(a); ! 202: } ! 203: } ! 204: ! 205: /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ ! 206: ! 207: chk1(pkt) char *pkt; { ! 208: unsigned int chk; ! 209: chk = chk2(pkt); ! 210: chk = (((chk & 0300) >> 6) + chk) & 077; ! 211: return(chk); ! 212: } ! 213: ! 214: /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ ! 215: ! 216: unsigned ! 217: chk2(pkt) CHAR *pkt; { ! 218: long chk; unsigned int m; ! 219: m = (parity) ? 0177 : 0377; ! 220: for (chk = 0; *pkt != '\0'; pkt++) ! 221: chk += *pkt & m; ! 222: return(chk & 07777); ! 223: } ! 224: ! 225: ! 226: /* C H K 3 -- Compute a type-3 Kermit block check. */ ! 227: /* ! 228: Calculate the 16-bit CRC of a null-terminated string using a byte-oriented ! 229: tableless algorithm invented by Andy Lowry (Columbia University). The ! 230: magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1. ! 231: Note - this function could be adapted for strings containing imbedded 0's ! 232: by including a length argument. Another note - Replacing this function by ! 233: a table lookup version might speed things up. ! 234: */ ! 235: chk3(s) char *s; { ! 236: unsigned int c, q; ! 237: LONG crc = 0; ! 238: ! 239: while ((c = *s++) != '\0') { ! 240: if (parity) c &= 0177; /* Strip any parity */ ! 241: q = (crc ^ c) & 017; /* Low-order nibble */ ! 242: crc = (crc >> 4) ^ (q * 010201); ! 243: q = (crc ^ (c >> 4)) & 017; /* High order nibble */ ! 244: crc = (crc >> 4) ^ (q * 010201); ! 245: } ! 246: return(crc); ! 247: } ! 248: ! 249: /* Functions for sending various kinds of packets */ ! 250: ! 251: ack() { /* Send an ordinary acknowledgment. */ ! 252: spack('Y',pktnum,0,""); /* No data. */ ! 253: nxtpkt(&pktnum); /* Increment the packet number. */ ! 254: } /* Note, only call this once! */ ! 255: ! 256: ack1(s) char *s; { /* Send an ACK with data. */ ! 257: spack('Y',pktnum,strlen(s),s); /* Send the packet. */ ! 258: nxtpkt(&pktnum); /* Increment the packet number. */ ! 259: } /* Only call this once! */ ! 260: ! 261: nack() { /* Negative acknowledgment. */ ! 262: spack('N',pktnum,0,""); /* NAK's never have data. */ ! 263: } ! 264: ! 265: resend() { /* Send the old packet again. */ ! 266: if (spktl) /* If buffer has something, */ ! 267: ttol(sndpkt,spktl); /* resend it, */ ! 268: else nack(); /* otherwise send a NAK. */ ! 269: ! 270: debug(F111,"resend",sndpkt,spktl); ! 271: screen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Say resend occurred */ ! 272: if (pktlog) { ! 273: zsout(ZPFILE,"s-"); ! 274: zsoutl(ZPFILE,"(resend)"); /* Log packet if desired */ ! 275: } ! 276: } ! 277: ! 278: errpkt(reason) char *reason; { /* Send an error packet. */ ! 279: encstr(reason); ! 280: spack('E',pktnum,size,data); ! 281: clsif(); clsof(1); ! 282: screen(SCR_TC,0,0l,""); ! 283: } ! 284: ! 285: scmd(t,dat) char t, *dat; { /* Send a packet of the given type */ ! 286: encstr(dat); /* Encode the command string */ ! 287: spack(t,pktnum,size,data); ! 288: } ! 289: ! 290: srinit() { /* Send R (GET) packet */ ! 291: encstr(cmarg); /* Encode the filename. */ ! 292: spack('R',pktnum,size,data); /* Send the packet. */ ! 293: } ! 294: ! 295: nxtpkt(num) int *num; { ! 296: prvpkt = *num; /* Save previous */ ! 297: *num = (*num + 1) % 64; /* Increment packet number mod 64 */ ! 298: } ! 299: ! 300: sigint() { /* Terminal interrupt handler */ ! 301: errpkt("User typed ^C"); ! 302: doexit(GOOD_EXIT); /* Exit program */ ! 303: } ! 304: ! 305: /* R P A C K -- Read a Packet */ ! 306: ! 307: /* ! 308: rpack reads a packet and returns the packet type, or else Q if the ! 309: packet was invalid, or T if a timeout occurred. Upon successful return, sets ! 310: the values of global rsn (received sequence number), rln (received ! 311: data length), and rdatap (pointer to null-terminated data field). ! 312: */ ! 313: rpack() { ! 314: int i, j, x, try, type, lp; /* Local variables */ ! 315: CHAR pbc[4]; /* Packet block check */ ! 316: CHAR *sohp = recpkt; /* Pointer to SOH */ ! 317: CHAR e; /* Packet end character */ ! 318: ! 319: rsn = rln = -1; /* In case of failure. */ ! 320: *recpkt = '\0'; /* Clear receive buffer. */ ! 321: ! 322: e = (turn) ? turnch : eol; /* Use any handshake char for eol */ ! 323: ! 324: /* Try several times to get a "line". This allows for hosts that echo our */ ! 325: /* normal CR packet terminator as CRLF. Don't diagnose CRLF as an */ ! 326: /* invalid packet. */ ! 327: ! 328: #define TTITRY 3 ! 329: ! 330: for (try = 0; try < TTITRY; try++) { /* Try x times to get a "line". */ ! 331: j = ttinl(recpkt,MAXRP,timint,e); ! 332: if (j < 0) { ! 333: if (j < -1) doexit(BAD_EXIT); /* Bail out if ^C^C typed. */ ! 334: debug(F101,"rpack: ttinl fails","",j); ! 335: screen(SCR_PT,'T',(long)pktnum,""); ! 336: return('T'); /* Otherwise, call it a timeout. */ ! 337: } ! 338: tlci += j; /* All OK, Count the characters. */ ! 339: flci += j; ! 340: ! 341: for (i = 0; (recpkt[i] != stchr) && (i < j); i++) ! 342: sohp++; /* Find mark */ ! 343: if (i++ < j) break; /* Found it. */ ! 344: } ! 345: if (try >= TTITRY) return('Q'); /* Diagnose bad packet. */ ! 346: ! 347: debug(F111,"ttinl",sohp,j); /* Log packet if requested. */ ! 348: if (pktlog) { ! 349: zsout(ZPFILE,"r-"); ! 350: zsoutl(ZPFILE,sohp); ! 351: } ! 352: lp = i; /* Remember LEN position. */ ! 353: if ((j = xunchar(recpkt[i++])) == 0) { ! 354: if ((j = lp+5) > MAXRP) return('Q'); /* Long packet */ ! 355: x = recpkt[j]; /* Header checksum. */ ! 356: recpkt[j] = '\0'; /* Calculate & compare. */ ! 357: if (xunchar(x) != chk1(recpkt+lp)) return('Q'); ! 358: recpkt[j] = x; /* Checksum ok. */ ! 359: rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctu; ! 360: j = 3; /* Data offset. */ ! 361: } else if (j < 3) { ! 362: debug(F101,"rpack packet length less than 3","",j); ! 363: return('Q'); ! 364: } else { ! 365: rln = j - bctu - 2; /* Regular packet */ ! 366: j = 0; /* No extended header */ ! 367: } ! 368: rsn = xunchar(recpkt[i++]); /* Sequence number */ ! 369: type = recpkt[i++]; /* Packet type */ ! 370: i += j; /* Where data begins */ ! 371: rdatap = recpkt+i; /* The data itself */ ! 372: if ((j = rln + i) > MAXRP ) { ! 373: debug(F101,"packet sticks out too far","",j); ! 374: return('Q'); /* Find block check */ ! 375: } ! 376: /** debug(F101,"block check at","",j); **/ ! 377: for (x = 0; x < bctu; x++) /* Copy it */ ! 378: pbc[x] = recpkt[j+x]; ! 379: ! 380: pbc[x] = '\0'; ! 381: /** debug(F110,"block check",pbc,bctu); **/ ! 382: recpkt[j] = '\0'; /* Null-terminate data */ ! 383: ! 384: switch (bctu) { /* Check the block check */ ! 385: case 1: ! 386: if (xunchar(*pbc) != chk1(recpkt+lp)) { ! 387: debug(F110,"checked chars",recpkt+lp,0); ! 388: debug(F101,"block check","",xunchar(*pbc)); ! 389: debug(F101,"should be","",chk1(recpkt+lp)); ! 390: return('Q'); ! 391: } ! 392: break; ! 393: case 2: ! 394: x = xunchar(*pbc) << 6 | xunchar(pbc[1]); ! 395: if (x != chk2(recpkt+lp)) { ! 396: debug(F110,"checked chars",recpkt+lp,0); ! 397: debug(F101,"block check","", x); ! 398: debug(F101,"should be","", chk2(recpkt+lp)); ! 399: return('Q'); ! 400: } ! 401: break; ! 402: case 3: ! 403: x = xunchar(*pbc) << 12 | xunchar(pbc[1]) << 6 | xunchar(pbc[2]); ! 404: if (x != chk3(recpkt+lp)) { ! 405: debug(F110,"checked chars",recpkt+lp,0); ! 406: debug(F101,"block check","",xunchar(*pbc)); ! 407: debug(F101,"should be","",chk1(recpkt+lp)); ! 408: return('Q'); ! 409: } ! 410: break; ! 411: default: return('Q'); ! 412: } ! 413: screen(SCR_PT,type,(long)rsn,sohp); /* Update screen */ ! 414: return(type); /* Return packet type */ ! 415: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.