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

Defined functions

ack defined in line 919; never used
ack1 defined in line 962; used 2 times
ackn defined in line 957; used 1 times
ackns defined in line 924; used 3 times
chk1 defined in line 848; used 8 times
chk2 defined in line 858; used 6 times
chk3 defined in line 873; used 3 times
chktimo defined in line 667; used 5 times
errpkt defined in line 1198; used 15 times
fstats defined in line 1571; used 3 times
input defined in line 226; never used
logpkt defined in line 1502; used 18 times
nack defined in line 976; used 5 times
rcalcpsz defined in line 1035; used 1 times
resend defined in line 1091; used 9 times
rpack defined in line 1243; used 4 times
scmd defined in line 1217; never used
spack defined in line 719; used 15 times
srinit defined in line 1229; never used
tstats defined in line 1568; used 2 times

Defined variables

VOID defined in line 1502; never used
crcta defined in line 204; used 1 times
crctb defined in line 208; used 1 times
numerrs defined in line 69; used 13 times
partab defined in line 71; used 12 times

Defined macros

NP_TELNET defined in line 28; used 2 times
Last modified: 1992-11-24
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3674
Valid CSS Valid XHTML 1.0 Strict