Annotation of coherent/e/bin/ckermit/ckcfn2.c, revision 1.1.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 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 */

unix.superglobalmegacorp.com

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