1: /* C K C F N 2 -- System-independent Kermit protocol support functions... */ 2: 3: /* ...Part 2 (continued from ckcfns.c) */ 4: 5: /* 6: Author: Frank da Cruz (fdc@watsun.cc.columbia.edu, FDCCU@CUVMA.BITNET), 7: Columbia University Center for Computing Activities. 8: First released January 1985. 9: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New 10: York. Permission is granted to any individual or institution to use this 11: software as long as it is not sold for profit. This copyright notice must be 12: retained. This software may not be included in commercial products without 13: written permission of Columbia University. 14: */ 15: /* 16: Note -- if you change this file, please amend the version number and date at 17: the top of ckcfns.c accordingly. 18: */ 19: 20: #include "ckcsym.h" /* Compilation options */ 21: #include "ckcdeb.h" /* Debugging and other symbols */ 22: #include "ckcasc.h" /* ASCII symbols */ 23: #include "ckcker.h" /* Kermit symbols */ 24: #include "ckcxla.h" /* Translation */ 25: 26: #ifdef TCPSOCKET /* For TELNET business in spack() */ 27: #ifndef NP_TELNET 28: #define NP_TELNET 1 29: extern int tn_nlm, ttnproto; 30: #endif /* NP_TELNET */ 31: #endif /* TCPSOCKET */ 32: 33: #ifdef DYNAMIC 34: extern struct pktinfo *s_pkt; /* array of pktinfo structures */ 35: extern struct pktinfo *r_pkt; /* array of pktinfo structures */ 36: #else 37: extern struct pktinfo s_pkt[]; /* array of pktinfo structures */ 38: extern struct pktinfo r_pkt[]; /* array of pktinfo structures */ 39: #endif /* DYNAMIC */ 40: 41: extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, sbufnum; 42: 43: extern int ttprty; /* from ckutio.c */ 44: extern int autopar; 45: 46: extern int spsiz, spmax, rpsiz, timint, timef, npad, ebq, ebqflg; 47: extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, network, flow; 48: extern int pktnum, sndtyp, bctr, bctu, bctl, rsn, rln, maxtry, size; 49: extern int osize, maxsize, spktl, rpktl, nfils, stdouf, warn, parity; 50: extern int turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn; 51: extern int hcflg, local, server, cxseen, czseen; 52: extern int nakstate, quiet, success, xitsta, what; 53: extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz; 54: 55: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, speed; 56: 57: extern char *cmarg, *cmarg2, filnam[], *hlptxt; 58: 59: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate; 60: extern CHAR *recpkt, *data, encbuf[], myinit[]; 61: extern CHAR *srvptr, stchr, mystch, *rdatap; 62: extern CHAR padbuf[]; 63: #ifdef DYNAMIC 64: extern CHAR *srvcmd; 65: #else 66: extern CHAR srvcmd[]; 67: #endif /* DYNAMIC */ 68: 69: int numerrs = 0; /* (PWP) total number packet errors so far */ 70: 71: static CHAR partab[] = { /* Even parity table for dopar(). */ 72: (CHAR) '\000', /* ANSI C casts '\ooo' constants */ 73: (CHAR) '\201', /* to signed char, so we have to */ 74: (CHAR) '\202', /* cast back to unsigned char... */ 75: (CHAR) '\003', 76: (CHAR) '\204', 77: (CHAR) '\005', 78: (CHAR) '\006', 79: (CHAR) '\207', 80: (CHAR) '\210', 81: (CHAR) '\011', 82: (CHAR) '\012', 83: (CHAR) '\213', 84: (CHAR) '\014', 85: (CHAR) '\215', 86: (CHAR) '\216', 87: (CHAR) '\017', 88: (CHAR) '\220', 89: (CHAR) '\021', 90: (CHAR) '\022', 91: (CHAR) '\223', 92: (CHAR) '\024', 93: (CHAR) '\225', 94: (CHAR) '\226', 95: (CHAR) '\027', 96: (CHAR) '\030', 97: (CHAR) '\231', 98: (CHAR) '\232', 99: (CHAR) '\033', 100: (CHAR) '\234', 101: (CHAR) '\035', 102: (CHAR) '\036', 103: (CHAR) '\237', 104: (CHAR) '\240', 105: (CHAR) '\041', 106: (CHAR) '\042', 107: (CHAR) '\243', 108: (CHAR) '\044', 109: (CHAR) '\245', 110: (CHAR) '\246', 111: (CHAR) '\047', 112: (CHAR) '\050', 113: (CHAR) '\251', 114: (CHAR) '\252', 115: (CHAR) '\053', 116: (CHAR) '\254', 117: (CHAR) '\055', 118: (CHAR) '\056', 119: (CHAR) '\257', 120: (CHAR) '\060', 121: (CHAR) '\261', 122: (CHAR) '\262', 123: (CHAR) '\063', 124: (CHAR) '\264', 125: (CHAR) '\065', 126: (CHAR) '\066', 127: (CHAR) '\267', 128: (CHAR) '\270', 129: (CHAR) '\071', 130: (CHAR) '\072', 131: (CHAR) '\273', 132: (CHAR) '\074', 133: (CHAR) '\275', 134: (CHAR) '\276', 135: (CHAR) '\077', 136: (CHAR) '\300', 137: (CHAR) '\101', 138: (CHAR) '\102', 139: (CHAR) '\303', 140: (CHAR) '\104', 141: (CHAR) '\305', 142: (CHAR) '\306', 143: (CHAR) '\107', 144: (CHAR) '\110', 145: (CHAR) '\311', 146: (CHAR) '\312', 147: (CHAR) '\113', 148: (CHAR) '\314', 149: (CHAR) '\115', 150: (CHAR) '\116', 151: (CHAR) '\317', 152: (CHAR) '\120', 153: (CHAR) '\321', 154: (CHAR) '\322', 155: (CHAR) '\123', 156: (CHAR) '\324', 157: (CHAR) '\125', 158: (CHAR) '\126', 159: (CHAR) '\327', 160: (CHAR) '\330', 161: (CHAR) '\131', 162: (CHAR) '\132', 163: (CHAR) '\333', 164: (CHAR) '\134', 165: (CHAR) '\335', 166: (CHAR) '\336', 167: (CHAR) '\137', 168: (CHAR) '\140', 169: (CHAR) '\341', 170: (CHAR) '\342', 171: (CHAR) '\143', 172: (CHAR) '\344', 173: (CHAR) '\145', 174: (CHAR) '\146', 175: (CHAR) '\347', 176: (CHAR) '\350', 177: (CHAR) '\151', 178: (CHAR) '\152', 179: (CHAR) '\353', 180: (CHAR) '\154', 181: (CHAR) '\355', 182: (CHAR) '\356', 183: (CHAR) '\157', 184: (CHAR) '\360', 185: (CHAR) '\161', 186: (CHAR) '\162', 187: (CHAR) '\363', 188: (CHAR) '\164', 189: (CHAR) '\365', 190: (CHAR) '\366', 191: (CHAR) '\167', 192: (CHAR) '\170', 193: (CHAR) '\371', 194: (CHAR) '\372', 195: (CHAR) '\173', 196: (CHAR) '\374', 197: (CHAR) '\175', 198: (CHAR) '\176', 199: (CHAR) '\377' 200: }; 201: 202: /* CRC generation tables */ 203: 204: static long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L, 205: 051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L, 206: 0153215L, 0163416L, 0173617L }; 207: 208: static long crctb[16] = { 0L, 010611L, 021422L, 031233L, 043044L, 209: 053655L, 062466L, 072277L, 0106110L, 0116701L, 0127532L, 0137323L, 0145154L, 210: 0155745L, 0164576L, 0174367L }; 211: 212: 213: /* I N P U T -- Attempt to read packet number 'pktnum'. */ 214: 215: /* 216: This is the function that feeds input to Kermit's finite state machine, 217: in the form of a character in the range 32-126, normally a packet type 218: (uppercase letter) or pseudo-packet-type (lowercase letter). 219: 220: If a special start state is in effect, that state is returned as if it were 221: the type of an incoming packet. Otherwise: 222: 223: (fill in...) 224: */ 225: 226: int 227: input() { 228: int type; 229: int x = 0, y, k; 230: 231: debug(F101,"input sstate","",sstate); 232: debug(F101," nakstate","",nakstate); 233: debug(F000," sndtyp","",sndtyp); 234: 235: while (1) { /* Big loop... */ 236: 237: if (sstate != 0) { /* If a start state is in effect, */ 238: type = sstate; /* return it like a packet type, */ 239: sstate = 0; /* and then nullify it. */ 240: numerrs = 0; /* (PWP) no errors so far */ 241: return(type); 242: } 243: 244: if (nakstate) { /* This section for file receiver. */ 245: 246: if (wslots > 1) { /* If we're doing windows, */ 247: x = rseqtbl[winlo]; /* see if desired packet already in. */ 248: debug(F101," winlo","",winlo); 249: debug(F101," rseqtbl[winlo]","",rseqtbl[winlo]); 250: if (x > -1) { /* Already there? */ 251: if (r_pkt[x].pk_seq == winlo) { /* (double check) */ 252: rsn = winlo; /* Yes, return its info */ 253: debug(F101,"input return pre-stashed packet","",rsn); 254: dumprbuf(); 255: rdatap = r_pkt[x].pk_adr; /* like rpack would do. */ 256: rln = (int)strlen((char *) rdatap); 257: type = r_pkt[x].pk_typ; 258: break; 259: } 260: } 261: } 262: type = rpack(); /* Try to read a packet. */ 263: debug(F111,"input recv",(char *) rdatap,(int) type); 264: while (type == 'e') { /* Handle echoes */ 265: debug(F000,"echo discarded","",type); 266: type = rpack(); 267: } 268: if (type < -1) return('q'); /* Ctrl-C */ 269: if (type < 0) { /* Receive window full */ 270: /* Another thing to do here would be to delete */ 271: /* the highest packet and NAK winlo. But that */ 272: /* shouldn't be necessary since the other Kermit */ 273: /* should not have sent a packet outside the window. */ 274: debug(F101,"rpack receive window full","",0); 275: dumprbuf(); 276: errpkt((CHAR *)"Receive window full."); 277: strcpy((char *)recpkt,"Receive window full."); 278: type = 'E'; 279: break; 280: } 281: dumprbuf(); 282: 283: if (chkint() < 0) { /* Check for console interrupts. */ 284: errpkt((CHAR *)"User cancelled."); 285: strcpy((char *)recpkt,"User cancelled."); 286: type = 'E'; 287: break; 288: } 289: if (type == 'E') { 290: debug(F101,"input got E, nakstate","",nakstate); 291: break; /* Error packet */ 292: } 293: if (type == 'Q') { /* Crunched packet. */ 294: crunched++; 295: numerrs++; 296: if (nack(winlo) < 0) { /* Request resend of window-low.. */ 297: debug(F101,"input sent too many naks","",winlo); 298: errpkt((CHAR *)"Too many retries."); 299: strcpy((char *)recpkt,"Sent too many NAKs."); 300: type = 'E'; 301: break; 302: } else continue; 303: } 304: if (type == 'T') { /* Timeout */ 305: #ifdef BULKNAKS 306: int z; 307: #endif 308: timeouts++; 309: debug(F101,"input receive-state timeout, winlo","",winlo); 310: #ifdef BULKNAKS 311: z = winlo + wslots; /* NAK all unACK'd packets */ 312: if (z > 63) z -= 64; 313: debug(F101,"input sending bulk NAKs, winlo","",winlo); 314: for (x = winlo; (x != z) && ttchk() == 0; x++) { 315: if (x < 0 || x > 63) break; 316: if (rseqtbl[x] < 0) { 317: if (nack(x) < 0) { 318: debug(F101,"input sent too many naks","",winlo); 319: errpkt((CHAR *)"Too many retries."); 320: strcpy(recpkt,"Sent too many NAKs."); 321: type = 'E'; 322: break; 323: } 324: } 325: } 326: #else /* NAK only the packet at window-low */ 327: debug(F101,"input sending NAK for winlo","",winlo); 328: if (nack(winlo) < 0) { 329: debug(F101,"input sent too many naks","",winlo); 330: errpkt((CHAR *)"Too many retries."); 331: strcpy((char *)recpkt,"Sent too many NAKs."); 332: type = 'E'; 333: break; 334: } 335: #endif /* BULKNAKS */ 336: continue; 337: } 338: 339: /* Got the packet we want, done. */ 340: 341: if (rsn == winlo) { 342: debug(F101,"input rsn=winlo","",rsn); 343: break; 344: } 345: 346: /* Got a packet out of order. */ 347: 348: debug(F101,"input recv got packet out of order","",rsn); 349: k = rseqtbl[rsn]; /* Get window slot of this packet. */ 350: debug(F101,"input recv rseqtbl[rsn]","",k); 351: if (k < 0) { 352: debug(F101,"input recv can't find index for rcvd pkt","",rsn); 353: errpkt((CHAR *)"internal error number 21"); 354: strcpy((char *)recpkt,"Sliding windows protocol error."); 355: type = 'E'; 356: break; 357: } 358: y = chkwin(rsn,winlo,wslots); /* See what window it's in. */ 359: debug(F101,"input recv chkwin","",y); 360: if (y == 1) { /* Previous window. */ 361: #ifdef COMMENT 362: ackn(rsn); /* Send empty ACK */ 363: #else 364: resend(rsn); 365: #endif /* COMMENT */ 366: freerpkt(rsn); /* Get rid of received packet */ 367: continue; 368: } else { /* In this window or out of range */ 369: if (y < 0) /* If out of range entirely, */ 370: freerpkt(rsn); /* release its buffer */ 371: /* 372: We have received a packet, but not the one we want. If we do nothing, 373: we could be in for a lengthy timeout/retry cycle. It would seem to 374: make sense to send a NAK for the most desired packet (winlo). But 375: consider this scenario: a packet arrived damaged so we NAK'd it above; 376: then packets winlo+1, winlo+2, ... winlo+n arrive, each one making us 377: send a NAK for winlo, so the other Kermit gets n NAKs for winlo, and 378: either would have to resend it n times, or if n > retry limit, give up 379: because of too many retries. So we compromise: If a packet arrives 380: that is not the most desired packet (winlo), we NAK winlo, BUT ONLY IF 381: it has not been NAK'd before. 382: */ 383: if (s_pkt[k].pk_rtr == 0) { /* Have we been here before? */ 384: if (nack(winlo) < 0) { /* No, NAK winlo. */ 385: errpkt((CHAR *)"Too many retries."); /* Too many */ 386: strcpy((char *)recpkt,"Timed out."); /* Give up */ 387: type = 'E'; 388: break; 389: } else continue; 390: } else continue; 391: } 392: /*!!!*/ 393: } else { /* Otherwise file sender... */ 394: 395: if (wslots > 1) { /* Packet at winlo already ACK'd? */ 396: if (sacktbl[winlo]) { /* If so, */ 397: sacktbl[winlo] = 0; /* Turn off the ACK'd flag */ 398: winlo = (winlo + 1) % 64; /* Rotate the window */ 399: type = 'Y'; /* And return ACK */ 400: debug(F101, 401: "input send returning pre-stashed ACK","", 402: winlo-1); 403: break; 404: } 405: } 406: type = rpack(); /* Try to read an acknowledgement */ 407: debug(F111,"input send",(char *) rdatap,(int) type); 408: while (type == 'e') { /* Handle echoes */ 409: debug(F000,"echo discarded","",type); 410: type = rpack(); 411: } 412: if (type == -2) return('q'); 413: if (type == -1) { 414: errpkt((CHAR *)"Internal error number 18"); 415: debug(F101," wslots","",wslots); 416: debug(F101," winlo","",winlo); 417: debug(F101," pktnum","",pktnum); 418: dumprbuf(); 419: strcpy((char *)recpkt,"Can't allocate receive buffer"); 420: type = 'E'; 421: break; 422: } 423: dumprbuf(); /* debugging */ 424: 425: if (chkint() < 0) { /* Check for console interrupts. */ 426: errpkt((CHAR *)"User cancelled."); 427: strcpy((char *)recpkt,"User cancelled."); 428: return(type = 'E'); 429: } 430: 431: /* got a packet */ 432: 433: if (type == 'E') { 434: debug(F101,"input send got E, nakstate","",nakstate); 435: break; /* Error packet */ 436: } 437: if (type == 'Q') { /* Crunched packet */ 438: crunched++; /* For statistics */ 439: numerrs++; /* For packet resizing */ 440: x = resend(winlo); /* Resend window-low */ 441: if (x < 0) { 442: type = 'E'; 443: errpkt(recpkt); 444: break; 445: } 446: continue; 447: } 448: if (type == 'T') { /* Timeout waiting for ACKs. */ 449: timeouts++; /* Count it */ 450: numerrs++; /* Count an error too */ 451: debug(F101,"input send state timeout, winlo","",winlo); 452: 453: /* Retransmit the oldest un-ACK'd packet. */ 454: 455: debug(F101,"input send resending winlo","",winlo); 456: if (resend(winlo) < 0) { /* Check retries */ 457: debug(F101,"input send too many resends","",maxtry); 458: errpkt(recpkt); 459: return(type = 'E'); 460: } 461: continue; 462: } 463: 464: /* Got an actual normal packet */ 465: 466: y = chkwin(rsn,winlo,wslots); /* Is it in the window? */ 467: debug(F101,"input send rsn","",rsn); 468: debug(F101,"input send winlo","",winlo); 469: debug(F101,"input send chkwin","",y); 470: if (type == 'Y') { /* Got an ACK */ 471: if (y == 0) { /* In current window */ 472: x = sseqtbl[rsn]; /* Mark the packet as ACK'd */ 473: if (x > -1) s_pkt[x].pk_flg++; /* (old way) */ 474: sacktbl[rsn]++; /* (new way) */ 475: /* 476: NOTE: The following statement frees the buffer of the ACK we just got. 477: But the upper layers still need the data, like if it's the ACK to an I, 478: S, F, D, Z, or just about any kind of packet. So for now, freerbuf() 479: deallocates the buffer, but does not erase the data or destroy the pointer 480: to it. There's no other single place where these receive buffers can be 481: correctly freed (?) ... 482: */ 483: freerpkt(rsn); /* Free the ACK's buffer */ 484: freesbuf(rsn); /* *** Free the sent packet's buffer */ 485: if (rsn == winlo) { /* Got the one we want */ 486: sacktbl[winlo] = 0; 487: winlo = (winlo + 1) % 64; 488: debug(F101,"input send rotated send window","",winlo); 489: break; /* Return the ACK */ 490: } else { 491: debug(F101,"input send mark pkt","",rsn); 492: continue; /* Otherwise go read another packet */ 493: } 494: } else { /* ACK not in window, ignore */ 495: debug(F101,"input send ACK out of window","",rsn); 496: freerpkt(rsn); 497: continue; 498: } 499: } 500: if (type == 'N') { /* NAK */ 501: numerrs++; /* Count an error */ 502: debug(F101,"input send NAK","",rsn); 503: freerpkt(rsn); /* Free buffer where NAK lies. */ 504: if (y == 0) { /* In current window */ 505: debug(F100," in window","",0); 506: k = sseqtbl[rsn]; /* Get pointer to NAK'd packet. */ 507: x = 0; 508: if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) { 509: x = resend(winlo); /* Packet we haven't sent yet. */ 510: } else { 511: x = resend(rsn); /* Resend requested packet. */ 512: } 513: if (x < 0) { /* Resend error is fatal. */ 514: type = 'E'; 515: errpkt(recpkt); 516: break; 517: } else continue; /* Resend ok, go read another packet */ 518: } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */ 519: if (wslots > 1) { 520: debug( F101,"NAK for next packet, windowing","",rsn); 521: x = resend(winlo); /* Resend window-low */ 522: if (x < 0) { 523: type = 'E'; 524: errpkt(recpkt); 525: break; 526: } 527: continue; /* Go back and read another pkt */ 528: } 529: debug(F101,"NAK for next packet, no windowing","",rsn); 530: x = (rsn == 0) ? 63 : rsn - 1; 531: if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) { 532: resend(0); /* ACK for S or I packet missing */ 533: continue; /* so resend it. */ 534: } /* Else, treat NAK(n+1) as ACK(n) */ 535: if ((x = sseqtbl[x]) > -1) { 536: sacktbl[x]++; /* (new way) */ 537: s_pkt[x].pk_flg++; /* (old way) */ 538: } 539: type = 'Y'; /* Treat it as ACK for last pkt */ 540: break; 541: } else if (y > 0) { /* NAK for pkt we can't resend */ 542: debug(F101," NAK out of window","",rsn); /* bad... */ 543: type = 'E'; 544: errpkt((CHAR *)"NAK out of window"); 545: strcpy((char *)recpkt,"NAK out of window."); 546: break; 547: } else continue; /* Ignore other NAKs */ 548: } /* End of file-sender NAK handler */ 549: 550: if (rsn == winlo) { /* Not ACK, NAK, timeout, etc. */ 551: debug(F000,"input send unexpected type","",type); 552: break; 553: } 554: } /* End of file-sender section */ 555: } /* End of input() loop */ 556: if (wslots == 1) { 557: debug(F100,"input about to flush","",0); 558: ttflui(); /* Got what we want, clear input buffer. */ 559: } 560: if (!nakstate) /* When sending */ 561: rcalcpsz(); /* recalculate size every packet */ 562: debug(F000,"input returning type","",type); 563: return(type); /* Success, return packet type. */ 564: } 565: 566: /* D O P A R -- Add an appropriate parity bit to a character */ 567: 568: /* 569: (PWP) this is still used in the Mac terminal emulator, so we have to keep it 570: */ 571: CHAR 572: #ifdef CK_ANSIC 573: dopar(register CHAR ch) 574: #else 575: dopar(ch) register CHAR ch; 576: #endif /* CK_ANSIC */ 577: { 578: register unsigned int a; 579: if (!parity) return((CHAR) (ch & 255)); else a = ch & 127; 580: switch (parity) { 581: case 'e': return(partab[a]); /* Even */ 582: case 'm': return((CHAR) (a | 128)); /* Mark */ 583: case 'o': return((CHAR) (partab[a] ^ 128)); /* Odd */ 584: case 's': return((CHAR) a); /* Space */ 585: default: return((CHAR) a); /* Something illegal */ 586: } 587: } 588: 589: #ifdef PARSENSE 590: /* P A R C H K -- Check if Kermit packet has parity */ 591: 592: /* 593: Call with s = pointer to packet, start = packet start character, n = length. 594: Returns 0 if packet has no parity, -1 on error, or, if packet has parity: 595: 'e' for even, 'o' for odd, 'm' for mark. Space parity cannot be sensed. 596: So a return value of 0 really means either space or none. 597: Returns -2 if parity has already been checked during this protocol operation. 598: */ 599: int 600: #ifdef CK_ANSIC 601: parchk(CHAR *s, CHAR start, int n) 602: #else 603: parchk(s,start,n) CHAR *s, start; int n; 604: #endif /* CK_ANSIC */ 605: /* parchk */ { 606: CHAR s0, s1, s2, s3; 607: 608: debug(F101,"parchk n","",n); 609: debug(F101,"parchk start","",start); 610: 611: s0 = s[0] & 0x7f; /* Mark field (usually Ctrl-A) */ 612: 613: if (s0 != start || n < 5) return(-1); /* Not a valid packet */ 614: 615: /* Look at packet control fields, which never have 8th bit set */ 616: /* First check for no parity, most common case. */ 617: 618: if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0) 619: return(0); /* No parity or space parity */ 620: 621: /* Check for mark parity */ 622: 623: if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80) 624: return('m'); /* Mark parity */ 625: 626: /* Packet has some kind of parity */ 627: /* Make 7-bit copies of control fields */ 628: 629: s1 = s[1] & 0x7f; /* LEN */ 630: s2 = s[2] & 0x7f; /* SEQ */ 631: s3 = s[3] & 0x7f; /* TYPE */ 632: 633: /* Check for even parity */ 634: 635: if ((s[0] == partab[s0]) && 636: (s[1] == partab[s1]) && 637: (s[2] == partab[s2]) && 638: (s[3] == partab[s3])) 639: return('e'); 640: 641: /* Check for odd parity */ 642: 643: if ((s[0] != partab[s0]) && 644: (s[1] != partab[s1]) && 645: (s[2] != partab[s2]) && 646: (s[3] != partab[s3])) 647: return('o'); 648: 649: /* Otherwise it's probably line noise. Let checksum calculation catch it. */ 650: 651: return(-1); 652: } 653: #endif /* PARSENSE */ 654: 655: /* 656: Check to make sure timeout intervals are long enough to allow maximum 657: length packets to get through before the timer goes off. If not, the 658: timeout interval is adjusted upwards. 659: 660: This routine is called at the beginning of a transaction, before we 661: know anything about the delay characteristics of the line. It works 662: only for serial communication devices; it trusts the speed reported by 663: the operating system. 664: 665: Call with a timout interval. Returns it, adjusted if necessary. 666: */ 667: int 668: chktimo(timo,flag) int timo, flag; { 669: long cps, z; int x, y; 670: debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */ 671: debug(F101,"chktimo flag","",flag); 672: 673: if (flag) /* Don't change timeout if user */ 674: return(timo); /* gave SET SEND TIMEOUT command. */ 675: debug(F101,"chktimo spmax","",spmax); 676: debug(F101,"chktimo urpsiz","",urpsiz); 677: 678: speed = ttgspd(); /* Get current speed. */ 679: if (speed > 0L && !network) { 680: cps = speed / 10L; /* Convert to chars per second */ 681: if (cps > 0L) { 682: long plen; /* Maximum of send and rcv pkt size */ 683: z = cps * (long) timo; /* Chars per timeout interval */ 684: z -= z / 10L; /* Less 10 percent */ 685: plen = spmax; 686: if (urpsiz > spmax) plen = urpsiz; 687: debug(F101,"chktimo plen","",plen); 688: if (z < plen) { /* Compare with packet size */ 689: x = (int) ((long) plen / cps); /* Adjust if necessary */ 690: y = x / 10; /* Add 10 percent for safety */ 691: if (y < 2) y = 2; /* Or 2 seconds, whichever is more */ 692: x += y; 693: if (x > timo) /* If this is greater than current */ 694: timo = x; /* timeout, change the timeout */ 695: debug(F101,"chktimo new timo","",timo); 696: } 697: } 698: } 699: return(timo); 700: } 701: 702: /* S P A C K -- Construct and send a packet */ 703: 704: /* 705: spack() sends a packet of the given type, sequence number n, with len data 706: characters pointed to by d, in either a regular or extended- length packet, 707: depending on len. Returns the number of bytes actually sent, or else -1 708: upon failure. Uses global npad, padch, mystch, bctu, data. Leaves packet 709: fully built and null-terminated for later retransmission by resend(). 710: Updates global sndpktl (send-packet length). 711: 712: NOTE: The global pointer "data" is assumed to point into the 7th position 713: of a character array (presumably in packet buffer for the current packet). 714: It was used by getpkt() to build the packet data field. spack() fills in 715: the header to the left of the data pointer (the data pointer is defined 716: in getsbuf() in ckcfn3.c). If the address "d" is the same as "data", then 717: the packet's data field has been built "in place" and need not be copied. 718: */ 719: int 720: #ifdef CK_ANSIC 721: spack(char pkttyp, int n, int len, CHAR *d) 722: #else 723: spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d; 724: #endif /* CK_ANSIC */ 725: /* spack */ { 726: register int i; 727: int j, k, lp, longpkt, copy; 728: register CHAR *cp, *mydata; 729: unsigned crc; 730: 731: debug(F101,"spack n","",n); 732: debug(F111," data",data,data); 733: debug(F101," d","",d); 734: debug(F101," len","",len); 735: 736: copy = (d != data); /* Flag whether data must be copied */ 737: longpkt = (len + bctl + 2) > 94; /* Decide whether it's a long packet */ 738: mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */ 739: debug(F101," mydata","",mydata); 740: 741: k = sseqtbl[n]; /* Packet structure info for pkt n */ 742: debug(F101," sseqtbl[n]","",k); 743: if (k < 0) { 744: debug(F101,"spack sending packet out of window","",n); 745: } else { /* Record packet info */ 746: s_pkt[k].pk_adr = mydata; /* Remember address of packet. */ 747: s_pkt[k].pk_seq = n; /* Record sequence number */ 748: s_pkt[k].pk_typ = pkttyp; /* Record packet type */ 749: } 750: 751: spktl = 0; /* Initialize length of this packet */ 752: i = 0; /* and position in packet. */ 753: 754: /* Now fill the packet */ 755: 756: mydata[i++] = mystch; /* MARK */ 757: lp = i++; /* Position of LEN, fill in later */ 758: 759: mydata[i++] = tochar(n); /* SEQ field */ 760: mydata[i++] = pkttyp; /* TYPE field */ 761: j = len + bctl; /* Length of data + block check */ 762: if (longpkt) { /* Long packet? */ 763: int x; /* Work around SCO Xenix/286 */ 764: x = 95; /* compiler bug... */ 765: x = j / 95; 766: mydata[lp] = tochar(0); /* Yes, set LEN to zero */ 767: mydata[i++] = tochar(x); /* High part */ 768: mydata[i++] = tochar(j % 95); /* Low part */ 769: mydata[i] = '\0'; /* Header checksum */ 770: mydata[i++] = tochar(chk1(mydata+lp)); 771: } else mydata[lp] = tochar(j+2); /* Normal LEN */ 772: 773: if (copy) /* Data field built in place? */ 774: for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */ 775: else /* Otherwise, */ 776: i += len; /* Just skip past data field. */ 777: mydata[i] = '\0'; /* Null-terminate for checksum calc. */ 778: 779: switch (bctu) { /* Block check */ 780: case 1: /* 1 = 6-bit chksum */ 781: mydata[i++] = tochar(chk1(mydata+lp)); 782: break; 783: case 2: /* 2 = 12-bit chksum */ 784: j = chk2(mydata+lp); 785: mydata[i++] = (unsigned)tochar((j >> 6) & 077); 786: mydata[i++] = (unsigned)tochar(j & 077); 787: break; 788: case 3: /* 3 = 16-bit CRC */ 789: crc = chk3(mydata+lp); 790: mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12); 791: mydata[i++] = (unsigned)tochar((crc >> 6) & 077); 792: mydata[i++] = (unsigned)tochar(crc & 077); 793: break; 794: case 4: /* 2 = 12-bit chksum, blank-free */ 795: j = chk2(mydata+lp); 796: mydata[i++] = 797: (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1))); 798: mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1))); 799: break; 800: } 801: mydata[i++] = seol; /* End of line (packet terminator) */ 802: #ifdef TCPSOCKET 803: /* 804: If TELNET connection and packet terminator is carriage return, 805: we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE 806: (tn_nlm), to meet the TELNET specification. 807: */ 808: if (network && ttnproto == NP_TELNET && seol == CR) 809: mydata[i++] = tn_nlm ? LF : NUL; 810: #endif /* TCPSOCKET */ 811: mydata[i] = '\0'; /* Terminate string */ 812: logpkt('s',n,mydata); /* Log packet */ 813: 814: /* (PWP) add the parity quickly at the end */ 815: switch (parity) { 816: case 'e': /* Even */ 817: for (cp = &mydata[i-1]; cp >= mydata; cp--) 818: *cp = partab[*cp]; 819: break; 820: case 'm': /* Mark */ 821: for (cp = &mydata[i-1]; cp >= mydata; cp--) 822: *cp |= 128; 823: break; 824: case 'o': /* Odd */ 825: for (cp = &mydata[i-1]; cp >= mydata; cp--) 826: *cp = partab[*cp] ^ 128; 827: break; 828: case 's': /* Space */ 829: for (cp = &mydata[i-1]; cp >= mydata; cp--) 830: *cp &= 127; 831: break; 832: } 833: if (npad) ttol(padbuf,npad); /* Send any padding */ 834: spktl = i; /* Remember packet length */ 835: s_pkt[k].pk_len = spktl; /* also in packet info structure */ 836: if (ttol(mydata,spktl) < 0) return(-1); /* Send the packet */ 837: sndtyp = pkttyp; /* Remember packet type for echos */ 838: spackets++; /* Count it. */ 839: flco += spktl; /* Count the characters */ 840: tlco += spktl; /* for statistics... */ 841: dumpsbuf(); /* Dump send buffers to debug log */ 842: screen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */ 843: return(spktl); /* Return length */ 844: } 845: 846: /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ 847: 848: int 849: chk1(pkt) register CHAR *pkt; { 850: register unsigned int chk; 851: chk = chk2(pkt); 852: chk = (((chk & 0300) >> 6) + chk) & 077; 853: return((int) chk); 854: } 855: 856: /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ 857: 858: unsigned int 859: chk2(pkt) register CHAR *pkt; { 860: register long chk; register unsigned int m; 861: m = (parity) ? 0177 : 0377; 862: for (chk = 0; *pkt != '\0'; pkt++) 863: chk += *pkt & m; 864: return((unsigned int) (chk & 07777)); 865: } 866: 867: 868: /* C H K 3 -- Compute a type-3 Kermit block check. */ 869: /* 870: Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup 871: table. Assumes the argument string contains no embedded nulls. 872: */ 873: unsigned int 874: chk3(pkt) register CHAR *pkt; { 875: register long c, crc; 876: register unsigned int m; 877: m = (parity) ? 0177 : 0377; 878: for (crc = 0; *pkt != '\0'; pkt++) { 879: c = crc ^ (long)(*pkt & m); 880: crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]); 881: } 882: return((unsigned int) (crc & 0xFFFF)); 883: } 884: 885: int 886: nxtpkt() { /* Called by file sender */ 887: int j, n; 888: 889: debug(F101,"nxtpkt pktnum","",pktnum); 890: debug(F101,"nxtpkt winlo ","",winlo); 891: n = (pktnum + 1) % 64; /* Increment packet number mod 64 */ 892: #ifdef COMMENT 893: /* 894: Suggested by Alan Grieg. A packet can be sent out of window in 895: circumstances involving acks received out of order, ... Have to think 896: about this... 897: */ 898: if (chkwin(n,winlo,wslots)) { 899: debug(F101,"nxtpkt n not in window","",n); 900: return(-1); 901: } 902: #endif 903: j = getsbuf(n); /* Get a buffer for packet n */ 904: if (j < 0) { 905: debug(F101,"nxtpkt can't getsbuf","",j); 906: return(-1); 907: } 908: pktnum = n; 909: debug(F101,"nxtpkt bumped pktnum to","",pktnum); 910: return(0); 911: } 912: 913: /* Functions for sending ACKs and NAKs */ 914: 915: /* Note, we should only ACK the packet at window-low (winlo) */ 916: /* However, if an old packet arrives again (e.g. because the ACK we sent */ 917: /* earlier was lost), we ACK it again. */ 918: 919: int 920: ack() { /* Acknowledge the current packet. */ 921: return(ackns(winlo,(CHAR *)"")); 922: } 923: 924: int 925: ackns(n,s) int n; CHAR *s; { /* Acknowledge packet n */ 926: int j, k; 927: debug(F111,"ackns",s,n); 928: 929: k = rseqtbl[n]; /* First find received packet n. */ 930: debug(F101,"ackns k","",k); 931: #ifdef COMMENT 932: /* No need to set ACK'd bit, because we're gonna free the buffer now */ 933: if (k > -1) /* If in window */ 934: s_pkt[k].pk_flg++; /* mark the ack'd bit. */ 935: else 936: debug(F101,"ackns can't set ack'd bit","",k); 937: #endif 938: freesbuf(n); /* Free current send-buffer, if any */ 939: if ((j = getsbuf(n)) < 0) { 940: /* This can happen if we have to re-ACK an old packet that has */ 941: /* already left the window. It does no harm. */ 942: debug(F101,"ackns can't getsbuf","",n); 943: } 944: spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */ 945: debug(F101,"ackns winlo","",winlo); 946: debug(F101,"ackns n","",n); 947: if (n == winlo) { /* If we're acking winlo */ 948: if (k > -1) 949: freerbuf(k); /* don't need it any more */ 950: if (j > -1) 951: freesbuf(j); /* and don't need to keep ACK either */ 952: winlo = (winlo + 1) % 64; 953: } 954: return(0); 955: } 956: 957: int 958: ackn(n) int n; { /* Send ACK for packet number n */ 959: return(ackns(n,(CHAR *)"")); 960: } 961: 962: int 963: ack1(s) CHAR *s; { /* Send an ACK with data. */ 964: debug(F110,"ack1",(char *) s,0); 965: return(ackns(winlo, s)); 966: } 967: 968: /* N A C K -- Send a Negative ACKnowledgment. */ 969: /* 970: Call with the packet number, n, to be NAK'd. 971: Returns -1 if that packet has been NAK'd too many times, otherwise 0. 972: Btw, it is not right to return 0 under error conditions. This is 973: done because the -1 code is used for cancelling the file transfer. 974: More work is needed here. 975: */ 976: int 977: nack(n) int n; { 978: int i; 979: 980: if (n < 0 || n > 63) { 981: debug(F101,"nack bad pkt num","",n); 982: return(0); 983: } else debug(F101,"nack","",n); 984: if ((i = sseqtbl[n]) < 0) { /* If necessary */ 985: if (getsbuf(n) < 0) { /* get a buffer for this NAK */ 986: debug(F101,"nack can't getsbuf","",n); 987: return(0); 988: } else i = sseqtbl[n]; /* New slot number */ 989: } 990: if (s_pkt[i].pk_rtr++ > maxtry) /* How many times have we done this? */ 991: return(-1); /* Too many... */ 992: 993: /* Note, don't free this buffer. Eventually an ACK will come, and that */ 994: /* will set it free. If not, well, it's back to ground zero anyway... */ 995: 996: spack('N',n,0,(CHAR *) ""); /* NAKs never have data. */ 997: return(0); 998: } 999: 1000: /* 1001: * (PWP) recalculate the optimal packet length in the face of errors. 1002: * This is a modified version of the algorithm by John Chandler in Kermit/370, 1003: * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988. 1004: * 1005: * This implementation minimizes the total overhead equation, which is 1006: * 1007: * Total chars = file_chars + (header_len * num_packs) 1008: * + (errors * (header_len + packet_len)) 1009: * 1010: * Differentiate with respect to number of chars, solve for packet_len, get: 1011: * 1012: * packet_len = sqrt (file_chars * header_len / errors) 1013: */ 1014: 1015: /* 1016: (FDC) New super-simple algorithm. If there was an error in the most recent 1017: packet exchange, cut the send-packet size in half, down to a minimum of 20. 1018: If there was no error, increase the size by 5/4, up to the maximum negotiated 1019: length. Seems to be much more responsive than previous algorithm, which took 1020: forever to recover the original packet length, and it also went crazy under 1021: certain conditions. 1022: 1023: Here's another idea for packet length resizing that keeps a history of the 1024: last n packets. Push a 1 into the left end of an n-bit shift register if the 1025: current packet is good, otherwise push a zero. The current n-bit value, w, of 1026: this register is a weighted sum of the noise hits for the last n packets, with 1027: the most recent weighing the most. The current packet length is some function 1028: of w and the negotiated packet length, like: 1029: 1030: (2^n - w) / (2^n) * (negotiated length) 1031: 1032: If the present resizing method causes problems, think about this one a little 1033: more. 1034: */ 1035: VOID 1036: rcalcpsz() { 1037: 1038: #ifdef COMMENT 1039: /* Old way */ 1040: register long x, q; 1041: if (numerrs == 0) return; /* bounds check just in case */ 1042: 1043: /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */ 1044: /* an ACK is 5+bctr */ 1045: 1046: /* first set x = per packet overhead */ 1047: if (wslots > 1) 1048: x = (long) (npad+5+bctr); /* only the packet, don't count the ack */ 1049: else 1050: x = (long) (npad+5+3+bctr+5+bctr); 1051: 1052: /* then set x = packet length ** 2 */ 1053: x = x * ( ffc / (long) numerrs); /* careful of overflow */ 1054: 1055: /* calculate the long integer sqrt(x) quickly */ 1056: q = 500; 1057: q = (q + x/q) >> 1; 1058: q = (q + x/q) >> 1; 1059: q = (q + x/q) >> 1; 1060: q = (q + x/q) >> 1; /* should converge in about 4 steps */ 1061: if ((q > 94) && (q < 130)) /* break-even point for long packets */ 1062: q = 94; 1063: if (q > spmax) q = spmax; /* maximum bounds */ 1064: if (q < 10) q = 10; /* minimum bounds */ 1065: spsiz = q; /* set new send packet size */ 1066: debug(F101,"rcalcpsiz","",q); 1067: #else 1068: /* New way */ 1069: if (spackets < 3) return; 1070: debug(F101,"rcalcpsiz numerrs","",numerrs); 1071: debug(F101,"rcalcpsiz spsiz","",spsiz); 1072: if (numerrs) 1073: spsiz = spsiz / 2; 1074: else 1075: spsiz = (spsiz / 4) * 5; 1076: if (spsiz < 20) spsiz = 20; 1077: if (spsiz > spmax) spsiz = spmax; 1078: debug(F101,"rcalcpsiz new spsiz","",spsiz); 1079: numerrs = 0; 1080: return; 1081: #endif 1082: } 1083: 1084: /* R E S E N D -- Retransmit packet n. */ 1085: 1086: /* 1087: Returns 0 or positive on success (the number of retries for packet n). 1088: On failure, returns a negative number, and an error message is placed 1089: in recpkt. 1090: */ 1091: int 1092: resend(n) int n; { /* Send packet n again. */ 1093: int j, k; 1094: 1095: debug(F101,"resend seq","",n); 1096: 1097: k = chkwin(n,winlo,wslots); /* See if packet in current window */ 1098: j = -1; /* Assume it's lost */ 1099: if (k == 0) j = sseqtbl[n]; /* See if we still have a copy of it */ 1100: if (k != 0 || j < 0) { /* If not.... */ 1101: if (nakstate && k == 1) { 1102: /* 1103: Packet n is in the previous window and we are the file receiver. 1104: We already sent the ACK and deallocated its buffer so we can't just 1105: retransmit the ACK. Rather than give up, we try some tricks... 1106: */ 1107: if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */ 1108: /* 1109: If the packet number is 0, and we're at the beginning of a protocol 1110: operation (spackets < 63), then we have to resend the ACK to an I or S 1111: packet, complete with parameters in the data field. So we take a chance and 1112: send a copy of the parameters in an ACK packet with block check type 1. 1113: */ 1114: int bctlsav; /* Temporary storage */ 1115: int bctusav; 1116: bctlsav = bctl; /* Save current block check length */ 1117: bctusav = bctu; /* and type */ 1118: bctu = bctl = 1; /* Set block check to 1 */ 1119: spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit); 1120: logpkt('#',n,(CHAR *)"<reconstructed>"); /* Log it */ 1121: bctu = bctusav; /* Restore block check type */ 1122: bctl = bctlsav; /* and length */ 1123: 1124: } else { /* Not the first packet */ 1125: /* 1126: It's not the first packet of the protocol operation. It's some other packet 1127: that we have already ACK'd and forgotten about. So we take a chance and 1128: send an empty ACK using the current block-check type. Usually this will 1129: work out OK (like when acking Data packets), and no great harm will be done 1130: if it was some other kind of packet (F, etc). If we are requesting an 1131: interruption of the file transfer, the flags are still set, so we'll catch 1132: up on the next packet. 1133: */ 1134: spack('Y',n,0,(CHAR *) ""); 1135: logpkt('#',n,(CHAR *)"<faith>"); /* Log it */ 1136: } 1137: retrans++; 1138: screen(SCR_PT,'%',(long)pktnum,"(resend)"); 1139: return(0); 1140: } else { 1141: /* 1142: Packet number is not in current or previous window. We seem to hit this 1143: code occasionally at the beginning of a transaction, for apparently no good 1144: reason. Let's just log it for debugging, send nothing, and try to proceed 1145: with the protocol rather than killing it. 1146: */ 1147: debug(F101,"RESEND PKT NOT IN WINDOW","",n); 1148: debug(F101,"RESEND k","",k); 1149: #ifdef COMMENT 1150: sprintf((char *)recpkt, 1151: " resend error: NIW, n=%d, k=%d.",n,k); 1152: return(-2); 1153: #else 1154: return(0); 1155: #endif /* COMMENT */ 1156: } 1157: } 1158: 1159: /* OK, it's in the window and it's not lost. */ 1160: 1161: debug(F101,"resend pktinfo index","",k); 1162: 1163: if (s_pkt[j].pk_rtr++ > maxtry) { /* Found it but over retry limit */ 1164: strcpy((char *)recpkt,"Too many retries."); 1165: return(-1); 1166: } 1167: debug(F101," retry","",s_pkt[j].pk_rtr); /* OK so far */ 1168: dumpsbuf(); /* (debugging) */ 1169: if (s_pkt[j].pk_typ == ' ') { /* Incompletely formed packet */ 1170: if (nakstate) { /* (This shouldn't happen any more) */ 1171: nack(n); 1172: retrans++; 1173: screen(SCR_PT,'%',(long)pktnum,"(resend)"); 1174: return(s_pkt[j].pk_rtr); 1175: } else { /* No packet to resend! */ 1176: #ifdef COMMENT 1177: /* 1178: This happened (once) while sending a file with 2 window slots and typing 1179: X to the sender to cancel the file. But since we're cancelling anyway, 1180: no need to give a scary message. 1181: */ 1182: sprintf((char *)recpkt, 1183: "resend logic error: NPS, n=%d, j=%d.",n,j); 1184: return(-2); 1185: #else 1186: /* Just ignore it. */ 1187: return(0); 1188: #endif /* COMMENT */ 1189: } 1190: } 1191: ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len); /* Everything ok, send the packet */ 1192: retrans++; /* Count a retransmission */ 1193: screen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Tell user about resend */ 1194: logpkt('S',n,s_pkt[j].pk_adr); /* Log the resent packet */ 1195: return(s_pkt[j].pk_rtr); /* Return the number of retries. */ 1196: } 1197: 1198: int 1199: errpkt(reason) CHAR *reason; { /* Send an error packet. */ 1200: int x, y; 1201: encstr(reason); 1202: y = spack('E',pktnum,size,encbuf+7); 1203: x = quiet; quiet = 1; /* Close files silently. */ 1204: clsif(); clsof(1); 1205: quiet = x; 1206: #ifdef COMMENT 1207: screen(SCR_TC,0,0l,""); 1208: #endif /* COMMENT */ 1209: if (what < W_CONNECT) 1210: xitsta |= what; /* Remember what failed. */ 1211: success = 0; 1212: return(y); 1213: } 1214: 1215: /* scmd() -- Send a packet of the given type */ 1216: 1217: int 1218: #ifdef CK_ANSIC 1219: scmd(char t, CHAR *dat) 1220: #else 1221: scmd(t,dat) char t; CHAR *dat; 1222: #endif /* CK_ANSIC */ 1223: /* scmd */ { 1224: encstr(dat); /* Encode the command string */ 1225: spack(t,pktnum,size,(CHAR *)(encbuf+7)); 1226: return(0); 1227: } 1228: 1229: VOID 1230: srinit() { /* Send R (GET) packet */ 1231: encstr((CHAR *)cmarg); /* Encode the filename. */ 1232: spack('R',pktnum,size,encbuf+7); /* Send the packet. */ 1233: } 1234: 1235: /* R P A C K -- Read a Packet */ 1236: 1237: /* 1238: rpack reads a packet and returns the packet type, or else Q if the 1239: packet was invalid, or T if a timeout occurred. Upon successful return, sets 1240: the values of global rsn (received sequence number), rln (received 1241: data length), and rdatap (pointer to null-terminated data field). 1242: */ 1243: int 1244: rpack() { 1245: register int i, j, x, lp; /* Local variables */ 1246: int k, type, chklen; 1247: unsigned crc; 1248: CHAR pbc[4]; /* Packet block check */ 1249: CHAR *sohp; /* Pointer to SOH */ 1250: CHAR e; /* Packet end character */ 1251: 1252: debug(F101,"entering rpack, pktnum","",pktnum); 1253: k = getrbuf(); /* Get a new packet input buffer. */ 1254: debug(F101,"rpack getrbuf","",k); 1255: if (k < 0) return(-1); /* Return like this if none free. */ 1256: recpkt = r_pkt[k].bf_adr; 1257: *recpkt = '\0'; /* Clear receive buffer. */ 1258: sohp = recpkt; /* Initialize pointers to it. */ 1259: rdatap = recpkt; 1260: rsn = rln = -1; /* In case of failure. */ 1261: e = (turn) ? turnch : eol; /* Use any handshake char for eol */ 1262: 1263: /* Try to get a "line". */ 1264: 1265: #ifdef PARSENSE 1266: #ifdef UNIX 1267: /* 1268: So far the final turn argument is only for ck[uvd]tio.c. Should be added 1269: to the others too. (turn == handshake character.) 1270: */ 1271: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr,turn); 1272: #else 1273: #ifdef VMS 1274: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr,turn); 1275: #else 1276: #ifdef datageneral 1277: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr,turn); 1278: #else 1279: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr); 1280: #endif /* datageneral */ 1281: #endif /* VMS */ 1282: #endif /* UNIX */ 1283: if (parity != ttprty) autopar = 1; 1284: parity = ttprty; 1285: #else 1286: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e); 1287: #endif /* PARSENSE */ 1288: if (j < 0) { 1289: debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */ 1290: freerbuf(k); /* Free this buffer */ 1291: if (j < -1) { /* Bail out if ^C^C typed. */ 1292: debug(F101,"rpack ^C server","",server); 1293: debug(F101,"rpack ^C en_fin","",en_fin); 1294: if (server == 0) return(j); /* But not if in server mode */ 1295: else if (en_fin) return(j); /* with DISABLE FINISH */ 1296: } 1297: if (nakstate) /* call it a timeout. */ 1298: screen(SCR_PT,'T',(long)winlo,""); 1299: else 1300: screen(SCR_PT,'T',(long)pktnum,""); 1301: logpkt('r',-1,(CHAR *)"<timeout>"); 1302: if (flow == 1) ttoc(XON); /* In case of Xoff blockage. */ 1303: return('T'); 1304: } 1305: rpktl = j; 1306: tlci += j; /* All OK, Count the characters. */ 1307: flci += j; 1308: 1309: #ifndef PARSENSE 1310: /* THEN eliminate this loop... */ 1311: for (i = 0; (recpkt[i] != stchr) && (i < j); i++) 1312: sohp++; /* Find mark */ 1313: if (i++ >= j) { /* Didn't find it. */ 1314: logpkt('r',-1,"<timeout>"); 1315: freerbuf(k); 1316: return('T'); 1317: } 1318: #else 1319: i = 1; 1320: #endif /* PARSENSE */ 1321: 1322: rpackets++; 1323: lp = i; /* Remember LEN position. */ 1324: if ((j = xunchar(recpkt[i++])) == 0) { 1325: if ((j = lp+5) > MAXRP) return('Q'); /* Long packet */ 1326: x = recpkt[j]; /* Header checksum. */ 1327: recpkt[j] = '\0'; /* Calculate & compare. */ 1328: if (xunchar(x) != chk1(recpkt+lp)) { 1329: freerbuf(k); 1330: logpkt('r',-1,(CHAR *)"<crunched:hdr>"); 1331: return('Q'); 1332: } 1333: recpkt[j] = x; /* Checksum ok, put it back. */ 1334: rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl; 1335: j = 3; /* Data offset. */ 1336: } else if (j < 3) { 1337: debug(F101,"rpack packet length less than 3","",j); 1338: freerbuf(k); 1339: logpkt('r',-1,(CHAR *)"<crunched:len>"); 1340: return('Q'); 1341: } else { 1342: rln = j - bctl - 2; /* Regular packet */ 1343: j = 0; /* No extended header */ 1344: } 1345: rsn = xunchar(recpkt[i++]); /* Sequence number */ 1346: logpkt('r',rsn,sohp); 1347: if (rsn < 0 || rsn > 63) { 1348: debug(F101,"rpack bad sequence number","",rsn); 1349: freerbuf(k); 1350: logpkt('r',rsn,(CHAR *)"<crunched:seq>"); 1351: return('Q'); 1352: } 1353: /* 1354: If this packet has the same type as the packet just sent, assume it is 1355: an echo and ignore it. Don't even bother with the block check calculation: 1356: even if the packet is corrupted, we don't want to NAK an echoed packet. 1357: (And we certainly don't want to NAK an ACK or NAK!) 1358: */ 1359: type = recpkt[i++]; /* Get packet's TYPE field */ 1360: if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) { 1361: debug(F000,"rpack echo","",type); /* If it's an echo */ 1362: freerbuf(k); /* Free this buffer */ 1363: logpkt('#',rsn,(CHAR *)"<echo:ignored>"); 1364: return('e'); /* return special (lowercase) code */ 1365: } 1366: /* 1367: Separate the data from the block check, accounting for the case where 1368: a packet was retransmitted after the block check switched. 1369: */ 1370: if (type == 'I' || type == 'S') { /* I & S packets always have type 1 */ 1371: chklen = 1; 1372: rln = rln + bctl - 1; 1373: } else if (type == 'N') { /* A NAK packet never has data */ 1374: chklen = xunchar(recpkt[lp]) - 2; 1375: rln = rln + bctl - chklen; 1376: } else chklen = bctl; 1377: debug(F101,"rpack bctl","",bctl); 1378: debug(F101,"rpack chklen","",chklen); 1379: 1380: i += j; /* Buffer index of DATA field */ 1381: rdatap = recpkt+i; /* Pointer to DATA field */ 1382: if ((j = rln + i) > r_pkt[k].bf_len ) { /* Make sure it fits */ 1383: debug(F101,"packet sticks out too far","",j); 1384: freerbuf(k); 1385: logpkt('r',rsn,(CHAR *)"<overflow>"); 1386: return('Q'); 1387: } 1388: 1389: for (x = 0; x < chklen; x++) /* Copy the block check */ 1390: pbc[x] = recpkt[j+x]; 1391: pbc[x] = '\0'; /* Null-terminate block check string */ 1392: recpkt[j] = '\0'; /* and the packet DATA field. */ 1393: 1394: if (chklen == 2 && bctu == 4) { /* Adjust for Blank-Free-2 */ 1395: chklen = 4; /* (chklen is now a misnomer...) */ 1396: debug(F100,"rpack block check B","",0); 1397: } 1398: switch (chklen) { /* Check the block check */ 1399: case 1: /* Type 1, 6-bit checksum */ 1400: if (xunchar(*pbc) != chk1(recpkt+lp)) { 1401: debug(F110,"checked chars",recpkt+lp,0); 1402: debug(F101,"block check","",(int) xunchar(*pbc)); 1403: debug(F101,"should be","",chk1(recpkt+lp)); 1404: freerbuf(k); 1405: logpkt('r',-1,(CHAR *)"<crunched:chk1>"); 1406: return('Q'); 1407: } 1408: break; 1409: case 2: /* Type 2, 12-bit checksum */ 1410: x = xunchar(*pbc) << 6 | xunchar(pbc[1]); 1411: if (x != chk2(recpkt+lp)) { /* No match */ 1412: if (type == 'E') { /* Allow E packets to have type 1 */ 1413: recpkt[j++] = pbc[0]; 1414: recpkt[j] = '\0'; 1415: if (xunchar(pbc[1]) == chk1(recpkt+lp)) 1416: break; 1417: else 1418: recpkt[--j] = '\0'; 1419: } 1420: debug(F110,"checked chars",recpkt+lp,0); 1421: debug(F101,"block check","", x); 1422: debug(F101,"should be","", (int) chk2(recpkt+lp)); 1423: freerbuf(k); 1424: logpkt('r',-1,(CHAR *)"<crunched:chk2>"); 1425: return('Q'); 1426: } 1427: break; 1428: case 3: /* Type 3, 16-bit CRC */ 1429: crc = (xunchar(pbc[0]) << 12) 1430: | (xunchar(pbc[1]) << 6) 1431: | (xunchar(pbc[2])); 1432: if (crc != chk3(recpkt+lp)) { 1433: if (type == 'E') { /* Allow E packets to have type 1 */ 1434: recpkt[j++] = pbc[0]; 1435: recpkt[j++] = pbc[1]; 1436: recpkt[j] = '\0'; 1437: if (xunchar(pbc[2]) == chk1(recpkt+lp)) 1438: break; 1439: else { j -=2; recpkt[j] = '\0'; } 1440: } 1441: debug(F110,"checked chars",recpkt+lp,0); 1442: debug(F101,"block check","",xunchar(*pbc)); 1443: debug(F101,"should be","",(int) chk3(recpkt+lp)); 1444: freerbuf(k); 1445: logpkt('r',-1,(CHAR *)"<crunched:chk3>"); 1446: return('Q'); 1447: } 1448: break; 1449: case 4: /* Type 4 = Type 2, no blanks. */ 1450: x = (unsigned)((xunchar(*pbc) - 1) << 6) | 1451: (unsigned)(xunchar(pbc[1]) - 1); 1452: if (x != chk2(recpkt+lp)) { 1453: if (type == 'E') { /* Allow E packets to have type 1 */ 1454: recpkt[j++] = pbc[0]; 1455: recpkt[j] = '\0'; 1456: if (xunchar(pbc[1]) == chk1(recpkt+lp)) 1457: break; 1458: else 1459: recpkt[--j] = '\0'; 1460: } 1461: debug(F101,"bad type B block check","",x); 1462: freerbuf(k); 1463: logpkt('r',-1,(CHAR *)"<crunched:chkb>"); 1464: return('Q'); 1465: } 1466: break; 1467: default: /* Shouldn't happen... */ 1468: freerbuf(k); 1469: logpkt('r',-1,(CHAR *)"<crunched:chkx>"); 1470: return('Q'); 1471: } 1472: debug(F101,"rpack block check OK","",rsn); 1473: 1474: /* Now we can believe the sequence number, and other fields. */ 1475: /* Here we violate strict principles of layering, etc, and look at the */ 1476: /* packet sequence number. If there's already a packet with the same */ 1477: /* number in the window, we remove this one so that the window will not */ 1478: /* fill up. */ 1479: 1480: if ((x = rseqtbl[rsn]) != -1) { /* Already a packet with this number */ 1481: retrans++; /* Count it for statistics */ 1482: debug(F101,"rpack got dup","",rsn); 1483: logpkt('r',rsn,(CHAR *)"<duplicate>"); 1484: freerbuf(x); /* Free old buffer, keep new packet. */ 1485: r_pkt[k].pk_rtr++; /* Count this as a retransmission. */ 1486: } 1487: 1488: /* New packet, not seen before, enter it into the receive window. */ 1489: 1490: rseqtbl[rsn] = k; /* Make back pointer */ 1491: r_pkt[k].pk_seq = rsn; /* Record in packet info structure */ 1492: r_pkt[k].pk_typ = type; /* Sequence, type,... */ 1493: r_pkt[k].pk_adr = rdatap; /* pointer to data buffer */ 1494: screen(SCR_PT,(char)type,(long)rsn,(char *)sohp); /* Update screen */ 1495: return(type); /* Return packet type */ 1496: } 1497: 1498: /* L O G P K T -- Log packet number n, pointed to by s. */ 1499: 1500: /* c = 's' (send) or 'r' (receive) */ 1501: 1502: VOID 1503: #ifdef CK_ANSIC 1504: logpkt(char c,int n, CHAR *s) 1505: #else 1506: logpkt(c,n,s) char c; int n; CHAR *s; 1507: #endif /* CK_ANSIC */ 1508: /* logpkt */ { 1509: char plog[20]; 1510: if (pktlog && *s) { 1511: if (n < 0) 1512: sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60)); 1513: else 1514: sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60)); 1515: if (zsout(ZPFILE,plog) < 0) pktlog = 0; 1516: else if (zsoutl(ZPFILE,(char *)s) < 0) pktlog = 0; 1517: } 1518: } 1519: 1520: #ifdef TLOG 1521: 1522: /* T S T A T S -- Record statistics in transaction log */ 1523: 1524: VOID 1525: tstats() { 1526: char *tp; 1527: ztime(&tp); /* Get time stamp */ 1528: tlog(F110,"End of transaction",tp,0L); /* Record it */ 1529: 1530: if (filcnt < 1) return; /* If no files, done. */ 1531: 1532: /* If multiple files, record character totals for all files */ 1533: 1534: if (filcnt > 1) { 1535: tlog(F101," files","",filcnt); 1536: tlog(F101," total file characters ","",tfc); 1537: tlog(F101," communication line in ","",tlci); 1538: tlog(F101," communication line out ","",tlco); 1539: } 1540: 1541: /* Record timing info for one or more files */ 1542: 1543: tlog(F101," elapsed time (seconds) ","",(long) tsecs); 1544: if (tsecs > 0) { 1545: long lx; 1546: lx = (tfc * 10L) / (long) tsecs; 1547: tlog(F101," effective data rate ","",lx/10L); 1548: if (speed <= 0L) speed = ttgspd(); 1549: if (speed > 0L && speed != 8880L && network == 0) { 1550: lx = (lx * 100L) / speed; 1551: tlog(F101," efficiency (percent) ","",lx); 1552: } 1553: } 1554: tlog(F100,"","",0L); /* Leave a blank line */ 1555: } 1556: 1557: /* F S T A T S -- Record file statistics in transaction log */ 1558: 1559: VOID 1560: fstats() { 1561: tfc += ffc; 1562: tlog(F100," end of file","",0L); 1563: tlog(F101," file characters ","",ffc); 1564: tlog(F101," communication line in ","",flci); 1565: tlog(F101," communication line out ","",flco); 1566: } 1567: #else /* NOTLOG */ 1568: VOID 1569: tstats() {} 1570: 1571: VOID 1572: fstats() { 1573: tfc += ffc; 1574: } 1575: #endif /* TLOG */