Annotation of researchv10dc/lbin/kermit/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:  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.