Annotation of researchv10dc/lbin/kermit/ckcfn2.c, revision 1.1

1.1     ! root        1: /*  C K C F N 2  --  System-independent Kermit protocol support functions... */
        !             2: 
        !             3: /*  ...Part 2 (continued from ckcfns.c)  */
        !             4: /*
        !             5:  Modified July 87 to incorporate changes from Jim Noble of
        !             6:  Planning Research Corp for Macintosh Megamax C support.
        !             7: */
        !             8: /*
        !             9:  Author: Frank da Cruz (SY.FDC@CU20B),
        !            10:  Columbia University Center for Computing Activities, January 1985.
        !            11:  Copyright (C) 1985, Trustees of Columbia University in the City of New York.
        !            12:  Permission is granted to any individual or institution to use, copy, or
        !            13:  redistribute this software so long as it is not sold for profit, provided this
        !            14:  copyright notice is retained. 
        !            15: */
        !            16: /*
        !            17:  Note -- if you change this file, please amend the version number and date at
        !            18:  the top of ckcfns.c accordingly.
        !            19: */
        !            20: 
        !            21: #include "ckcsym.h"            /* Conditional compilation (for Macintosh) */
        !            22: #include "ckcker.h"
        !            23: #include "ckcdeb.h"
        !            24: 
        !            25: extern int spsiz, rpsiz, timint, npad, ebq, ebqflg, rpt, rptq, rptflg, capas;
        !            26: extern int pktnum, prvpkt, sndtyp, bctr, bctu, rsn, rln, maxtry, size;
        !            27: extern int osize, maxsize, spktl, nfils, stdouf, warn, timef, parity, speed;
        !            28: extern int turn, turnch,  delay, displa, pktlog, tralog, seslog, xflg, mypadn;
        !            29: extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen;
        !            30: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize;
        !            31: extern char *cmarg, *cmarg2, **cmlist;
        !            32: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, *hlptxt;
        !            33: extern CHAR filnam[], sndpkt[], recpkt[], data[], srvcmd[];
        !            34: extern CHAR *srvptr, stchr, mystch, *rdatap;
        !            35: 
        !            36: char *strcpy();                                /* Forward declarations */
        !            37: unsigned chk2();                       /* of non-int functions */
        !            38: CHAR dopar();                          /* ... */
        !            39: 
        !            40: static CHAR partab[] = {               /* Even parity table for dopar() */
        !            41: 
        !            42:     '\000', '\201', '\202', '\003', '\204', '\005', '\006', '\207',
        !            43:     '\210', '\011', '\012', '\213', '\014', '\215', '\216', '\017',
        !            44:     '\220', '\021', '\022', '\223', '\024', '\225', '\226', '\027',
        !            45:     '\030', '\231', '\232', '\033', '\234', '\035', '\036', '\237',
        !            46:     '\240', '\041', '\042', '\243', '\044', '\245', '\246', '\047',
        !            47:     '\050', '\251', '\252', '\053', '\254', '\055', '\056', '\257',
        !            48:     '\060', '\261', '\262', '\063', '\264', '\065', '\066', '\267',
        !            49:     '\270', '\071', '\072', '\273', '\074', '\275', '\276', '\077',
        !            50:     '\300', '\101', '\102', '\303', '\104', '\305', '\306', '\107',
        !            51:     '\110', '\311', '\312', '\113', '\314', '\115', '\116', '\317',
        !            52:     '\120', '\321', '\322', '\123', '\324', '\125', '\126', '\327',
        !            53:     '\330', '\131', '\132', '\333', '\134', '\335', '\336', '\137',
        !            54:     '\140', '\341', '\342', '\143', '\344', '\145', '\146', '\347',
        !            55:     '\350', '\151', '\152', '\353', '\154', '\355', '\356', '\157',
        !            56:     '\360', '\161', '\162', '\363', '\164', '\365', '\366', '\167',
        !            57:     '\170', '\371', '\372', '\173', '\374', '\175', '\176', '\377'
        !            58: };
        !            59: 
        !            60: /*  I N P U T  --  Attempt to read packet number 'pktnum'.  */
        !            61: 
        !            62: /*
        !            63:  This is the function that feeds input to Kermit's finite state machine.
        !            64: 
        !            65:  If a special start state is in effect, that state is returned as if it were
        !            66:  the type of an incoming packet.  Otherwise:
        !            67: 
        !            68:  . If the desired packet arrives within MAXTRY tries, return its type,
        !            69:    with its data stored in the global 'data' array.
        !            70: 
        !            71:  . If the previous packet arrives again, resend the last packet and wait for
        !            72:    another to come in.
        !            73: 
        !            74:  . If the desired packet does not arrive within MAXTRY tries, return indicating
        !            75:    that an error packet should be sent.
        !            76: */
        !            77: 
        !            78: input() {
        !            79:     int type, numtry;
        !            80: 
        !            81:     if (sstate != 0) {                 /* If a start state is in effect, */
        !            82:        type = sstate;                  /* return it like a packet type, */
        !            83:        sstate = 0;                     /* and then nullify it. */
        !            84:        return(type);
        !            85:     } else type = rpack();             /* Else, try to read a packet. */
        !            86: 
        !            87: debug(F111,"input",rdatap,type);
        !            88: 
        !            89: /* If it's the same packet we just sent, it's an echo.  Read another. */
        !            90: 
        !            91:     if (type == sndtyp) type = rpack();
        !            92: 
        !            93:     chkint();                          /* Check for console interrupts. */
        !            94: /*
        !            95:  If previous packet again, a timeout pseudopacket, or a bad packet, try again.
        !            96: */
        !            97:     for (numtry = 0;
        !            98:       (rsn == prvpkt || type == 'T' || type == 'Q' || type == 'N');
        !            99:       numtry++) {
        !           100:        if (numtry > maxtry) {          /* If too many tries, give up */
        !           101:            strcpy(data,"Timed out.");  /* and send a timeout error packet, */
        !           102:            rdatap = data;              /* and pretend we read one. */
        !           103:            return('E');
        !           104:        }
        !           105:        if (type == 'E') return('E');   /* Don't even bother about seq no */
        !           106:        if ((type == 'N') && (rsn == ((pktnum+1) & 63))) {
        !           107:                                        /* NAK for next packet */
        !           108:            return('Y');                /* is ACK for current. */
        !           109:        } else {    
        !           110:            resend();                   /* Else, send last packet again, */
        !           111:        }
        !           112:        if (sstate != 0) {              /* If an interrupt routine has set */
        !           113:            type = sstate;              /* sstate behind our back, return */
        !           114:            sstate = 0;                 /* that. */
        !           115:            *data = '\0';
        !           116:            return(type);
        !           117:        } else type = rpack();          /* Else try to read a packet. */
        !           118:        chkint();                       /* Look again for interruptions. */
        !           119:        if (type == sndtyp) type = rpack();
        !           120:     }
        !           121:     ttflui();                  /* Got what we want, clear input buffer. */
        !           122:     return(type);              /* Success, return packet type. */
        !           123: }
        !           124: 
        !           125: 
        !           126: /*  S P A C K  --  Construct and send a packet  */
        !           127: 
        !           128: /*
        !           129:  spack() sends a packet of the given type, sequence number n, with len
        !           130:  data characters pointed to by d, in either a regular or extended-
        !           131:  length packet, depending on length.  Returns the number of bytes
        !           132:  actually sent, or else -1 upon failure.  Uses global npad, padch,
        !           133:  mystch, bctu.  Leaves packet in null-terminated global sndpkt[] array for
        !           134:  later retransmission.  Updates global sndpktl (send-packet length).
        !           135: */
        !           136: 
        !           137: spack(type,n,len,d) char type, *d; int n, len; {
        !           138:     int i, j, lp; CHAR *sohp = sndpkt; CHAR pc;
        !           139: 
        !           140:     spktl = 0;
        !           141:     pc = dopar(padch);                 /* The pad character, if any. */
        !           142:     for (i = 0; i < npad; sndpkt[i++] = pc) /* Do any requested padding */
        !           143:       sohp++;
        !           144:     sndpkt[i++] = dopar(mystch);       /* MARK */
        !           145:     lp = i++;                          /* Position of LEN, fill in later */
        !           146:     sndpkt[i++] = dopar(tochar(n));    /* SEQ field */
        !           147:     sndpkt[i++] = dopar(sndtyp = type);        /* TYPE field */
        !           148:     j = len + bctu;                    /* True length */
        !           149:     if (j > 95) {                      /* Long packet? */
        !           150:         sndpkt[lp] = dopar(tochar(0)); /* Set LEN to zero */
        !           151:         sndpkt[i++] = dopar(tochar(j / 95)); /* High part */
        !           152:         sndpkt[i++] = dopar(tochar(j % 95)); /* Low part */
        !           153:         sndpkt[i] = '\0';              /* Header checksum */
        !           154:         sndpkt[i++] = dopar(tochar(chk1(sndpkt+lp)));
        !           155:     } else sndpkt[lp] = dopar(tochar(j+2)); /* Normal LEN */
        !           156: 
        !           157:     while (len-- > 0) sndpkt[i++] = dopar(*d++); /* Packet data */
        !           158:     sndpkt[i] = '\0';                  /* Null-terminate */
        !           159: 
        !           160:     switch (bctu) {                    /* Block check */
        !           161:        case 1:                         /* 1 = 6-bit chksum */
        !           162:            sndpkt[i++] = dopar(tochar(chk1(sndpkt+lp)));
        !           163:            break;
        !           164:        case 2:                         /* 2 = 12-bit chksum */
        !           165:            j = chk2(sndpkt+lp);
        !           166:            sndpkt[i++] = dopar( (unsigned) tochar((j >> 6) & 077));
        !           167:            sndpkt[i++] = dopar( (unsigned) tochar(j & 077));
        !           168:            break;
        !           169:         case 3:                                /* 3 = 16-bit CRC */
        !           170:            j = chk3(sndpkt+lp);
        !           171:            sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12));
        !           172:            sndpkt[i++] = dopar(tochar((j >> 6) & 077));
        !           173:            sndpkt[i++] = dopar(tochar(j & 077));
        !           174:            break;
        !           175:     }
        !           176:     sndpkt[i++] = dopar(seol);         /* End of line (packet terminator) */
        !           177:     sndpkt[i] = '\0';                  /* Terminate string */
        !           178:     if (ttol(sndpkt,i) < 0) return(-1);        /* Send the packet */
        !           179:     spktl = i;                         /* Remember packet length */
        !           180:     flco += spktl;                     /* Count the characters */
        !           181:     tlco += spktl;
        !           182:     if (pktlog) {                      /* If logging packets, log it */
        !           183:        zsout(ZPFILE,"s-");
        !           184:        if (*sndpkt) zsoutl(ZPFILE,sndpkt); else zsoutl(ZPFILE,sohp);
        !           185:     }  
        !           186:     screen(SCR_PT,type,(long)n,sohp);  /* Update screen */
        !           187:     return(i);                         /* Return length */
        !           188: }
        !           189: 
        !           190: /*  D O P A R  --  Add an appropriate parity bit to a character  */
        !           191: 
        !           192: CHAR
        !           193: dopar(ch) CHAR ch; {
        !           194:     int a;
        !           195:     if (!parity) return(ch & 255); else a = ch & 127;
        !           196:     switch (parity) {
        !           197:        case 'e':  return(partab[a]) & 255;        /* Even */
        !           198:        case 'm':  return(a | 128);                /* Mark */
        !           199:        case 'o':  return(partab[a] ^ 128) & 255;  /* Odd */
        !           200:        case 's':  return(a & 127);                /* Space */
        !           201:        default:   return(a);
        !           202:     }
        !           203: }
        !           204: 
        !           205: /*  C H K 1  --  Compute a type-1 Kermit 6-bit checksum.  */
        !           206: 
        !           207: chk1(pkt) char *pkt; {
        !           208:     unsigned int chk;
        !           209:     chk = chk2(pkt);
        !           210:     chk = (((chk & 0300) >> 6) + chk) & 077;
        !           211:     return(chk);
        !           212: }
        !           213: 
        !           214: /*  C H K 2  --  Compute the numeric sum of all the bytes in the packet.  */
        !           215: 
        !           216: unsigned
        !           217: chk2(pkt) CHAR *pkt; {
        !           218:     long chk; unsigned int m;
        !           219:     m = (parity) ? 0177 : 0377;
        !           220:     for (chk = 0; *pkt != '\0'; pkt++)
        !           221:       chk += *pkt & m;
        !           222:     return(chk & 07777);
        !           223: }
        !           224: 
        !           225: 
        !           226: /*  C H K 3  --  Compute a type-3 Kermit block check.  */
        !           227: /*
        !           228:  Calculate the 16-bit CRC of a null-terminated string using a byte-oriented
        !           229:  tableless algorithm invented by Andy Lowry (Columbia University).  The
        !           230:  magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1.
        !           231:  Note - this function could be adapted for strings containing imbedded 0's
        !           232:  by including a length argument.  Another note - Replacing this function by
        !           233:  a table lookup version might speed things up.
        !           234: */
        !           235: chk3(s) char *s; {
        !           236:     unsigned int c, q;
        !           237:     LONG crc = 0;
        !           238: 
        !           239:     while ((c = *s++) != '\0') {
        !           240:        if (parity) c &= 0177;          /* Strip any parity */
        !           241:        q = (crc ^ c) & 017;            /* Low-order nibble */
        !           242:        crc = (crc >> 4) ^ (q * 010201);
        !           243:        q = (crc ^ (c >> 4)) & 017;     /* High order nibble */
        !           244:        crc = (crc >> 4) ^ (q * 010201);
        !           245:     }
        !           246:     return(crc);
        !           247: }
        !           248: 
        !           249: /* Functions for sending various kinds of packets */
        !           250: 
        !           251: ack() {                                        /* Send an ordinary acknowledgment. */
        !           252:     spack('Y',pktnum,0,"");            /* No data. */
        !           253:     nxtpkt(&pktnum);                   /* Increment the packet number. */
        !           254: }                                      /* Note, only call this once! */
        !           255: 
        !           256: ack1(s) char *s; {                     /* Send an ACK with data. */
        !           257:     spack('Y',pktnum,strlen(s),s);     /* Send the packet. */
        !           258:     nxtpkt(&pktnum);                   /* Increment the packet number. */
        !           259: }                                      /* Only call this once! */
        !           260: 
        !           261: nack() {                               /* Negative acknowledgment. */
        !           262:     spack('N',pktnum,0,"");            /* NAK's never have data. */
        !           263: }
        !           264: 
        !           265: resend() {                             /* Send the old packet again. */
        !           266:     if (spktl)                         /* If buffer has something, */
        !           267:        ttol(sndpkt,spktl);             /* resend it, */
        !           268:     else nack();                       /* otherwise send a NAK. */
        !           269:     
        !           270:     debug(F111,"resend",sndpkt,spktl);
        !           271:     screen(SCR_PT,'%',(long)pktnum,"(resend)");        /* Say resend occurred */
        !           272:     if (pktlog) {
        !           273:        zsout(ZPFILE,"s-");
        !           274:        zsoutl(ZPFILE,"(resend)"); /* Log packet if desired */
        !           275:     }
        !           276: }
        !           277: 
        !           278: errpkt(reason) char *reason; {         /* Send an error packet. */
        !           279:     encstr(reason);
        !           280:     spack('E',pktnum,size,data);
        !           281:     clsif(); clsof(1);
        !           282:     screen(SCR_TC,0,0l,"");
        !           283: }
        !           284: 
        !           285: scmd(t,dat) char t, *dat; {            /* Send a packet of the given type */
        !           286:     encstr(dat);                       /* Encode the command string */
        !           287:     spack(t,pktnum,size,data);
        !           288: }
        !           289: 
        !           290: srinit() {                             /* Send R (GET) packet */
        !           291:     encstr(cmarg);                     /* Encode the filename. */
        !           292:     spack('R',pktnum,size,data);       /* Send the packet. */
        !           293: }
        !           294: 
        !           295: nxtpkt(num) int *num; {
        !           296:     prvpkt = *num;                     /* Save previous */
        !           297:     *num = (*num + 1) % 64;            /* Increment packet number mod 64 */
        !           298: }
        !           299: 
        !           300: sigint() {                             /* Terminal interrupt handler */
        !           301:     errpkt("User typed ^C");
        !           302:     doexit(GOOD_EXIT);                 /* Exit program */
        !           303: }
        !           304: 
        !           305: /* R P A C K  --  Read a Packet */
        !           306: 
        !           307: /*
        !           308:  rpack reads a packet and returns the packet type, or else Q if the
        !           309:  packet was invalid, or T if a timeout occurred.  Upon successful return, sets
        !           310:  the values of global rsn (received sequence number),  rln (received
        !           311:  data length), and rdatap (pointer to null-terminated data field).
        !           312: */
        !           313: rpack() {
        !           314:     int i, j, x, try, type, lp;                /* Local variables */
        !           315:     CHAR pbc[4];                       /* Packet block check */
        !           316:     CHAR *sohp = recpkt;               /* Pointer to SOH */
        !           317:     CHAR e;                            /* Packet end character */
        !           318: 
        !           319:     rsn = rln = -1;                    /* In case of failure. */
        !           320:     *recpkt = '\0';                    /* Clear receive buffer. */
        !           321:     
        !           322:     e = (turn) ? turnch : eol;         /* Use any handshake char for eol */
        !           323: 
        !           324: /* Try several times to get a "line".  This allows for hosts that echo our */
        !           325: /* normal CR packet terminator as CRLF.  Don't diagnose CRLF as an */
        !           326: /* invalid packet. */
        !           327: 
        !           328: #define TTITRY 3
        !           329: 
        !           330:     for (try = 0; try < TTITRY; try++) { /* Try x times to get a "line". */
        !           331:        j = ttinl(recpkt,MAXRP,timint,e); 
        !           332:        if (j < 0) {
        !           333:            if (j < -1) doexit(BAD_EXIT); /* Bail out if ^C^C typed. */
        !           334:            debug(F101,"rpack: ttinl fails","",j);
        !           335:            screen(SCR_PT,'T',(long)pktnum,"");
        !           336:            return('T');                /* Otherwise, call it a timeout. */
        !           337:        }
        !           338:        tlci += j;                      /* All OK, Count the characters. */
        !           339:        flci += j;
        !           340: 
        !           341:        for (i = 0; (recpkt[i] != stchr) && (i < j); i++)
        !           342:          sohp++;                       /* Find mark */
        !           343:        if (i++ < j) break;             /* Found it. */
        !           344:     }
        !           345:     if (try >= TTITRY) return('Q');    /* Diagnose bad packet. */
        !           346: 
        !           347:     debug(F111,"ttinl",sohp,j);                /* Log packet if requested. */
        !           348:     if (pktlog) {
        !           349:        zsout(ZPFILE,"r-");
        !           350:        zsoutl(ZPFILE,sohp);
        !           351:     }
        !           352:     lp = i;                            /* Remember LEN position. */
        !           353:     if ((j = xunchar(recpkt[i++])) == 0) {
        !           354:         if ((j = lp+5) > MAXRP) return('Q'); /* Long packet */
        !           355:        x = recpkt[j];                  /* Header checksum. */
        !           356:        recpkt[j] = '\0';               /* Calculate & compare. */
        !           357:        if (xunchar(x) != chk1(recpkt+lp)) return('Q');
        !           358:        recpkt[j] = x;                  /* Checksum ok. */
        !           359:        rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctu;
        !           360:        j = 3;                          /* Data offset. */
        !           361:     } else if (j < 3) {
        !           362:        debug(F101,"rpack packet length less than 3","",j);
        !           363:        return('Q');
        !           364:     } else {
        !           365:        rln = j - bctu - 2;             /* Regular packet */
        !           366:        j = 0;                          /* No extended header */
        !           367:     }
        !           368:     rsn = xunchar(recpkt[i++]);                /* Sequence number */
        !           369:     type = recpkt[i++];                        /* Packet type */
        !           370:     i += j;                            /* Where data begins */
        !           371:     rdatap = recpkt+i;                 /* The data itself */
        !           372:     if ((j = rln + i) > MAXRP ) {
        !           373:        debug(F101,"packet sticks out too far","",j);
        !           374:        return('Q'); /* Find block check */
        !           375:     }
        !           376: /** debug(F101,"block check at","",j); **/
        !           377:     for (x = 0; x < bctu; x++)         /* Copy it */
        !           378:       pbc[x] = recpkt[j+x];
        !           379: 
        !           380:     pbc[x] = '\0';
        !           381: /** debug(F110,"block check",pbc,bctu); **/
        !           382:     recpkt[j] = '\0';                  /* Null-terminate data */
        !           383: 
        !           384:     switch (bctu) {                    /* Check the block check */
        !           385:        case 1:
        !           386:            if (xunchar(*pbc) != chk1(recpkt+lp)) {
        !           387:                debug(F110,"checked chars",recpkt+lp,0);
        !           388:                debug(F101,"block check","",xunchar(*pbc));
        !           389:                debug(F101,"should be","",chk1(recpkt+lp));
        !           390:                return('Q');
        !           391:            }
        !           392:            break;
        !           393:        case 2:
        !           394:            x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
        !           395:            if (x != chk2(recpkt+lp)) {
        !           396:                debug(F110,"checked chars",recpkt+lp,0);
        !           397:                debug(F101,"block check","", x);
        !           398:                debug(F101,"should be","", chk2(recpkt+lp));
        !           399:                return('Q');
        !           400:            }
        !           401:            break;
        !           402:        case 3:
        !           403:            x = xunchar(*pbc) << 12 | xunchar(pbc[1]) << 6 | xunchar(pbc[2]);
        !           404:            if (x != chk3(recpkt+lp)) {
        !           405:                debug(F110,"checked chars",recpkt+lp,0);
        !           406:                debug(F101,"block check","",xunchar(*pbc));
        !           407:                debug(F101,"should be","",chk1(recpkt+lp));
        !           408:                return('Q');
        !           409:            }
        !           410:            break;
        !           411:        default: return('Q');
        !           412:     }
        !           413:     screen(SCR_PT,type,(long)rsn,sohp);        /* Update screen */
        !           414:     return(type);                      /* Return packet type */
        !           415: }

unix.superglobalmegacorp.com

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