|
|
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 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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.