Annotation of coherent/e/bin/cku179/ckcfn2.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.