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