home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / convergent.tar.gz / convergent.tar / ctfns2.c < prev    next >
C/C++ Source or Header  |  1993-01-20  |  13KB  |  451 lines

  1. /*  C K F N S 2  --  System-independent Kermit protocol support functions... */
  2.  
  3.  
  4. /* modified for CTOS C2.0 by Joel Dunn, UNC-CH, October 1986 */
  5. /* modified May 1992 by Doug Drury ITT-Federal Services */
  6. /* changed inlin() k < to k <= to enable timeouts */
  7. /* changed inlin () MAXTRY to timint at line 426  */
  8. /* changed MAXTRY to maxtry to implement variable retry limit */
  9. /* removed timing loop around flush of incoming characters so none lost */
  10. /*  ...Part 2 (continued from ckfns.c)  */
  11. /*
  12.  Note -- if you change this file, please amend the version number and date at
  13.  the top of ckfns.c accordingly.
  14. */
  15.  
  16. #include "ctermi.h"
  17.  
  18. extern int spsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas;
  19.  
  20. extern int pktnum, prvpkt, sndtyp, fsize, bctr, bctu, maxtry,
  21.  size, osize, maxsize, spktl, nfils, stdouf, warn, timef;
  22.  
  23. extern int parity, speed, turn, turnch, 
  24.  delaytime, displa, pktlog, tralog, seslog, xflg, mypadn;
  25.  
  26. extern long filcnt, ffc, flci, flco, tlci, tlco, tfc;
  27.  
  28. extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen;
  29.  
  30. extern char padch, mypadc, eol, reol, ctlq, myctlq, sstate, *hlptxt;
  31.  
  32. extern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, 
  33.  mystch;
  34.  
  35. extern char *cmarg, *cmarg2, **cmlist;
  36. char *strcpy();
  37.  
  38. /*  I N P U T  --  Attempt to read packet number 'pktnum'.  */
  39.  
  40. /*
  41.  This is the function that feeds input to Kermit's finite state machine.
  42.  
  43.  If a special start state is in effect, that state is returned as if it were
  44.  the type of an incoming packet.  Otherwise:
  45.  
  46.  . If the desired packet arrives within MAXTRY tries, return its type,
  47.    with its data stored in the global 'data' array.
  48.  
  49.  . If the previous packet arrives again, resend the last packet and wait for
  50.    another to come in.
  51.  
  52.  . If the desired packet does not arrive within MAXTRY tries, return indicating
  53.    that an error packet should be sent.
  54. */
  55.  
  56. input() {
  57.     int len, num, type, numtry;
  58.  
  59.     if (sstate != 0) {            /* If a start state is in effect, */
  60.     type = sstate;            /* return it like a packet type, */
  61.     sstate = 0;            /* and then nullify it. */
  62.     *data = '\0';
  63.     return(type);
  64.     } else type = rpack(&len,&num,data); /* Else, try to read a packet. */
  65.  
  66. /* If it's the same packet we just sent, it's an echo.  Read another. */
  67.  
  68.     if (type == sndtyp) type = rpack(&len,&num,data);
  69.  
  70.     chkint();                /* Check for console interrupts. */
  71. /*
  72.  If previous packet again, a timeout pseudopacket, or a bad packet, try again.
  73. */
  74.     for (numtry = 0;
  75.     num == prvpkt || type == 'N' || type == 'T' || type == 'Q' ;
  76.     numtry++)
  77.     {
  78.     if (numtry >= maxtry) {        /* If too many tries, give up */
  79.         strcpy(data,"Timed out.");    /* and send a timeout error packet. */
  80.         return('E');
  81.     }
  82.     resend();            /* Else, send last packet again, */
  83.     type = rpack(&len,&num,data);    /* and try to read a new one. */
  84.     chkint();            /* Look again for interruptions. */
  85.     }
  86.     return(type);            /* Success, return packet type. */
  87. }
  88.  
  89. /*  S P A C K  --  Construct and send a packet  */
  90.  
  91. spack(type,num,len,dat) char type, *dat; int num, len; {
  92.     int i,j;
  93.     
  94.     j = dopar(padch);
  95.     for (i = 0; i < npad; sndpkt[i++] = j)  /* Do any requested padding */
  96.         ;
  97.     sndpkt[i++] = dopar(mystch);    /* Start packet with the start char */
  98.     sndpkt[i++] = dopar(tochar(len+bctu+2));    /* Put in the length */
  99.     sndpkt[i++] = dopar(tochar(num));        /* The packet number */
  100.     sndpkt[i++] = sndtyp = dopar(type);        /* Packet type */
  101.  
  102.     for (j = len; j > 0; j-- ) sndpkt[i++] = dopar(*dat++); /* Data */
  103.  
  104.     sndpkt[i] = '\0';            /* Mark end for block check */
  105.     switch(bctu) {
  106.     case 1:             /* Type 1 - 6 bit checksum */
  107.         sndpkt[i++] = dopar(tochar(chk1(sndpkt+1)));
  108.         break;
  109.     case 2:                /* Type 2 - 12 bit checksum*/
  110.         j = chk2(sndpkt+1);
  111.         sndpkt[i++] = dopar(tochar((j & 07700) >> 6));
  112.         sndpkt[i++] = dopar(tochar(j & 077));
  113.         break;
  114.         case 3:                /* Type 3 - 16 bit CRC-CCITT */
  115.         j = chk3(sndpkt+1);
  116.         sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12));
  117.         sndpkt[i++] = dopar(tochar((j & 07700) >> 6));
  118.         sndpkt[i++] = dopar(tochar(j & 077));
  119.         break;
  120.     }
  121.     for (j = npad; j > 0; j-- ) sndpkt[i++] = dopar(padch); /* Padding */
  122.  
  123.     sndpkt[i++] = dopar(eol);        /* EOL character */
  124.     sndpkt[i] = '\0';            /* End of the packet */
  125.     ttol(sndpkt,spktl=i);        /* Send the packet just built */
  126.     flco += spktl;            /* Count the characters */
  127.     tlco += spktl;
  128.     if (pktlog) zsoutl(ZPFILE,sndpkt);    /* If logging packets, log it */
  129.     screen(type,(long)num,sndpkt);    /* Update screen */
  130. }
  131.  
  132. /*  D O P A R  --  Add an appropriate parity bit to a character  */
  133.  
  134. dopar (ch) char ch; {
  135.     int a; 
  136.  
  137.     switch (parity) {
  138.     case 'm':  return(ch | 128);        /* Mark */
  139.     case 's':  return(ch & 127);        /* Space */
  140.     case 'o':  ch |= 128;            /* Odd (fall thru) */
  141.     case 'e':                /* Even */
  142.         a = (ch & 15) ^ ((ch >> 4) & 15);
  143.         a = (a & 3) ^ ((a >> 2) & 3);
  144.         a = (a & 1) ^ ((a >> 1) & 1);
  145.         return(ch | (a << 7));
  146.     default:   return(ch);
  147.     }
  148. }
  149.  
  150. /*  C H K 1  --  Compute a type-1 Kermit 6-bit checksum.  */
  151.  
  152. chk1(pkt) char *pkt; {
  153.     int chk;
  154.     chk = chk2(pkt);
  155.     return((((chk & 0300) >> 6) + chk) & 077);
  156. }
  157.  
  158.  
  159. /*  C H K 2  --  Compute the numeric sum of all the bytes in the packet.  */
  160.  
  161. /* CTOS C1.0 barfed at original contents, hence changes to code to simplify
  162.    the expressions 'till it worked - now on C2.0, leave sleeping dogs alone */
  163.  
  164. chk2(pkt) char *pkt; {
  165.     unsigned int chk;
  166.     int p;
  167.     chk = 0;
  168.     while (*pkt != '\0') {
  169.     if (parity) p = *pkt & 0177;
  170.     else p = *pkt;
  171.     chk += p;
  172.     pkt++;
  173.     }
  174.     return(chk);
  175. }
  176.  
  177.  
  178. /*  C H K 3  --  Compute a type-3 Kermit block check.  */
  179. /*
  180.  Calculate the 16-bit CRC of a null-terminated string using a byte-oriented
  181.  tableless algorithm invented by Andy Lowry (Columbia University).  The
  182.  magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1.
  183.  Note - this function could adapted for strings containing imbedded 0's
  184.  by including a length argument.
  185. */
  186. chk3(s) char *s; {
  187.     unsigned int c, q;
  188.     LONG crc = 0;
  189.  
  190.     while ((c = *s++) != '\0') {
  191.     if (parity) c &= 0177;
  192.     q = (crc ^ c) & 017;        /* Low-order nibble */
  193.     crc = (crc >> 4) ^ (q * 010201);
  194.     q = (crc ^ (c >> 4)) & 017;    /* High order nibble */
  195.     crc = (crc >> 4) ^ (q * 010201);
  196.     }
  197.     return(crc);
  198. }
  199.  
  200. /* Functions for sending various kinds of packets */
  201.  
  202. ack() {                    /* Send an ordinary acknowledgment. */
  203.     spack('Y',pktnum,0,"");        /* No data. */
  204.     nxtpkt(&pktnum);            /* Increment the packet number. */
  205. }                    /* Note, only call this once! */
  206.  
  207. ack1(s) char *s; {            /* Send an ACK with data. */
  208.     spack('Y',pktnum,strlen(s),s);    /* Send the packet. */
  209.     nxtpkt(&pktnum);            /* Increment the packet number. */
  210. }                    /* Only call this once! */
  211.  
  212. nack() {                /* Negative acknowledgment. */
  213.     spack('N',pktnum,0,"");        /* NAK's never have data. */
  214. }
  215.  
  216. resend() {                /* Send the old packet again. */
  217.     int w;
  218.  
  219. /*    for (w = 0; w < timint - 2; w++) {   be extra sure no stuff is */
  220.     ttflui();            /* still comming in */
  221. /*    delay(5);
  222.     } */
  223.     ttol(sndpkt,spktl);
  224.     screen('%',(long)pktnum,sndpkt);
  225.     if (pktlog) zsoutl(ZPFILE,sndpkt);
  226. }
  227.  
  228. errpkt(reason) char *reason; {        /* Send an error packet. */
  229.     encstr(reason);
  230.     spack('E',pktnum,size,data);
  231. }
  232.  
  233. scmd(t,dat) char t, *dat; {        /* Send a packet of the given type */
  234.     encstr(dat);            /* Encode the command string */
  235.     ttflui();                /* Flush pending input. */
  236.     spack(t,pktnum,size,data);
  237. }
  238.  
  239. srinit() {                /* Send R (GET) packet */
  240.     encstr(cmarg);            /* Encode the filename. */
  241.     ttflui();                /* Flush pending input. */
  242.     spack('R',pktnum,size,data);    /* Send the packet. */
  243. }
  244.  
  245. nxtpkt(num) int *num; {
  246.     prvpkt = *num;            /* Save previous */
  247.     *num = (*num + 1) % 64;        /* Increment packet number mod 64 */
  248. }
  249.  
  250. sigint() {                /* Terminal interrupt handler */
  251.     errpkt("User typed ^C");
  252.     doexit(0);                /* Exit with status = 0 */
  253. }
  254.  
  255. /* R P A C K  --  Read a Packet */
  256.  
  257. rpack(l,n,dat) int *l, *n; char *dat; {
  258.     int i, j, x, done, pstart, pbl;
  259.     char chk[4], xchk[4], t, type;
  260.  
  261.     chk[3] = xchk[3] = 0;
  262.     i = inlin();            /* Read a line */
  263.     if (i != 0) {
  264.     debug(F101,"rpack: inlin","",i);
  265.     screen('T',(long)pktnum,"");
  266.     return('T');
  267.     }
  268.     debug(F110,"rpack: inlin ok, recpkt",recpkt,0);
  269.  
  270. /* Look for start of packet */
  271.  
  272.     for (i = 0; ((t = recpkt[i]) != stchr) && (i < RBUFL) ; i++)
  273.         ;
  274.     if (++i >= RBUFL) return('Q');    /* Skip rest if not found */
  275.  
  276. /* now "parse" the packet */
  277.  
  278.     debug(F101,"entering rpack with i","",i);
  279.     done = 0;
  280.     while (!done) {
  281.     debug(F101,"rpack starting at i","",i);
  282.         pstart = i;            /* remember where packet started */
  283.  
  284. /* length */
  285.  
  286.     if ((t = recpkt[i++]) == stchr) continue; /* Resynch if SOH */
  287.  
  288.    /***    if (t == 2) doexit(0); *** uncomment this to allow ^A^B cause exit ***/
  289.  
  290.     if (t == reol) return('Q');
  291.     *l = unchar(t);            /* Packet length */
  292.     debug(F101," pkt len","",*l);
  293.  
  294. /* sequence number */
  295.  
  296.     if ((t = recpkt[i++]) == stchr) continue;
  297.     if (t == reol) return('Q');
  298.     *n = unchar(t);
  299.     debug(F101,"rpack: n","",*n);
  300.  
  301. /* cont'd... */
  302.  
  303. /* ...rpack(), cont'd */
  304.  
  305.  
  306. /* type */
  307.  
  308.     if ((type = recpkt[i++]) == stchr) continue;
  309.     if (type == reol) return('Q');
  310.     debug(F101,"rpack: type","",type);
  311.  
  312.     if ((type == 'S') || (type == 'I')) pbl = 1;    /* Heuristics for  */
  313.     else if (type == 'N') pbl = *l - 2;    /* syncing block check type */
  314.     else pbl = bctu;
  315.  
  316.     *l -= (pbl + 2);        /* Now compute data length */
  317.     debug(F101,"rpack: bctu","",bctu);
  318.     debug(F101," pbl","",pbl);
  319.     debug(F101," data length","",*l);
  320.  
  321. /* data */
  322.  
  323.     dat[0] = '\0';            /* Return null string if no data */
  324.     for (j=0; j<*l; i++,j++)
  325.         if ((dat[j] = recpkt[i]) == stchr) continue;
  326.         else if (dat[j] == reol) return('Q');
  327.     dat[j] = '\0';
  328.  
  329. /* get the block check */
  330.  
  331.         debug(F110," packet chk",recpkt+i,0);
  332.         for (j = 0; j < pbl; j++) {
  333.         chk[j] = recpkt[i];
  334.         debug(F101," chk[j]","",chk[j]);
  335.         if (chk[j] == stchr) break;
  336.         if (chk[j] == eol) return('Q');
  337.         recpkt[i++] = '\0';
  338.     }
  339.     chk[j] = 0;
  340.     debug(F111," chk array, j",chk,j);
  341.     if (j != pbl) continue;        /* Block check right length? */
  342.     done = 1;            /* Yes, done. */
  343.     }
  344.  
  345. /* cont'd... */
  346.  
  347. /* ...rpack(), cont'd */
  348.  
  349.  
  350. /* Got packet, now check the block check */
  351.  
  352.     switch (pbl) {
  353.     case 1:
  354.         xchk[0] = tochar(chk1(&recpkt[pstart]));
  355.         if (chk[0] != xchk[0]) {
  356.         if (deblog) {
  357.             debug(F000,"rpack: chk","",chk[0]);
  358.             debug(F000," should be ","",xchk[0]);
  359.         }
  360.         screen('Q',(long)n,recpkt);
  361.         return('Q');
  362.         }
  363.         break;
  364.     case 2:
  365.         x = chk2(&recpkt[pstart]);
  366.         xchk[0] = tochar((x & 07700) >> 6);
  367.         xchk[1] = tochar(x & 077);
  368.         if (deblog) {
  369.         debug(F000," xchk[0]","=",xchk[0]);
  370.         debug(F000," xchk[1]","=",xchk[1]);
  371.         }
  372.         if ((xchk[0] != chk[0]) || (xchk[1] != chk[1])) {
  373.         debug(F100," bct2's don't compare","",0);
  374.         screen('Q',(long)n,recpkt);
  375.         return('Q');
  376.             }
  377.         break;
  378.     case 3:
  379.         x = chk3(&recpkt[pstart]);
  380.         xchk[0] = tochar(( (unsigned)(x & 0170000)) >> 12);
  381.         xchk[1] = tochar((x & 07700) >> 6);
  382.         xchk[2] = tochar(x & 077);
  383.         if (deblog) {
  384.         debug(F000," xchk[0]","=",xchk[0]);
  385.         debug(F000," xchk[1]","=",xchk[1]);
  386.         debug(F000," xchk[2]","=",xchk[2]);
  387.             }
  388.         if ((xchk[0] != chk[0]) || 
  389.             (xchk[1] != chk[1]) || 
  390.         (xchk[2] != chk[2])) {
  391.             debug(F100," bct3's don't compare","",0);
  392.             screen('Q',(long)n,recpkt);
  393.             return('Q');
  394.         }
  395.         break;
  396.         }
  397.  
  398. /* Good packet, return its type */
  399.  
  400.     ttflui();                /* Done, flush any remaining. */
  401.     screen(_tolower(type),(long)(*n),recpkt);    /* Update screen */
  402.     return(type);
  403. }
  404.  
  405. /*  I N C H R  --  Input character from communication line, with timeout  */
  406.         
  407. inchr(timo) int timo; {
  408.     int c;
  409.     c = ttinc(timo);
  410.     debug(F101,"inchr ttinc","",c);
  411.     if (c < 0) return(c);         /* Get a character */
  412.     if (parity) c = c & 0177;        /* If parity on, discard parity bit. */
  413.     debug(F101," after parity","",c);
  414.     return(c);
  415. }
  416.  
  417.  
  418. /*  I N L I N  -- Input a line (up to break char) from communication line  */
  419.  
  420. /*  Returns 0 on success, nonzero on failure  */
  421.  
  422. inlin() {
  423.     int e, i, j, k;
  424.  
  425.     e = (turn) ? turnch : reol;
  426.     i = j = k = 0;
  427.     if (parity) {
  428.         while ((j != e) && (i < RBUFL) && (k <= timint)) {
  429.            j = inchr(1);        /* Get char, 1 second timeout */
  430.         debug(F101,"inlin inchr","",j);
  431.         if (j < 0) k++;        /* Timed out. */
  432.         else {
  433.         if (j) recpkt[i++] = j;    /* Save it */
  434.         k = 0;            /* Reset timeout counter. */
  435.         }
  436.     }
  437.     } else {
  438.         i = ttinl(recpkt,RBUFL,timint,e);    /* Get them all at once */
  439.     if (i < 0) k = 1;
  440.     }
  441.     debug(F111,"inlin",recpkt,i);
  442.     debug(F101," timeouts","",k);
  443.     if (i < 1) return(1);
  444.     if (pktlog) zsoutl(ZPFILE,recpkt);
  445.     if (k > maxtry) return(1);
  446.     tlci += i;                /* Count the characters. */
  447.     flci += i;
  448.     recpkt[i+1] = '\0';            /* Terminate the input string. */
  449.     return(0);
  450. }
  451.