home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / pub / wkermit / lckfns3.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  11KB  |  372 lines

  1.  
  2. /*  C K C F N 3  --  System-independent Kermit protocol support functions... */
  3.  
  4. /*  ...Part 3 (continued from lckfns2.c)  */
  5. /*             Protocol functions for sliding window implementation.   */
  6. /*
  7.  Author: Jan A. van der Eyk, NUS Corp., July 1985.
  8.  
  9.  Columbia University Center for Computing Activities, January 1985.
  10.  Copyright (C) 1985, Trustees of Columbia University in the City of New York.
  11.  Permission is granted to any individual or institution to use, copy, or
  12.  redistribute this software so long as it is not sold for profit, provided this
  13.  copyright notice is retained.
  14. */
  15. /*
  16.  Note -- if you change this file, please amend the version number and date at
  17.  the top of lckfns.c accordingly.
  18. */
  19.  
  20. /*  IMPORTANT: When a window is being closed, i.e, after received an end of
  21.            file, pktnum should be reset to the received packet number.
  22. */
  23.  
  24.  
  25. #include "lckerm.h"
  26. #include "lckdeb.h"
  27.  
  28. int wndack[64], wndtry[64], wndlow, wndhgh, rpktno;
  29.  
  30. char wndata[64][94];
  31.  
  32. extern int cxseen, czseen,  sndtyp, prvpkt, pktnum, wndsiz, window;
  33.  
  34. extern int pktlog, sldwnd, quiet;
  35.  
  36.  
  37. extern int putfil();
  38.  
  39. extern char data[],sndpkt[], sstate;
  40.  
  41. char *strcpy();
  42.  
  43. /*  I N P U T  --  Attempt to read packet number 'pktnum'.  */
  44.  
  45. /*
  46.  This is the function that feeds input to Kermit's finite state machine.
  47.  
  48.  If a special start state is in effect, that state is returned as if it were
  49.  the type of an incoming packet.  Otherwise:
  50.  
  51.  . If the desired packet arrives within MAXTRY tries, return its type,
  52.    with its data stored in the global 'data' array.
  53.  
  54.  . If the previous packet arrives again, resend the last packet and wait for
  55.    another to come in.
  56.  
  57.  . If the desired packet does not arrive within MAXTRY tries, return indicating
  58.    that an error packet should be sent.
  59. */
  60.  
  61. input() {
  62.     int len, num, type;
  63.     static int numtry;
  64.  
  65.     if (!window) numtry = 0;
  66.  
  67.     while ( numtry <= MAXTRY )
  68.        {
  69.     if (sstate != 0) {        /* If an interrupt routine has set  */
  70.         type = sstate;        /* sstate behind our back, or        */
  71.         sstate = 0;         /* if a start state is in effect,   */
  72.         *data = '\0';               /* nulify start state and return it */
  73.         numtry = 0;         /* like a packet type  */
  74.         return(type);
  75.     }
  76.  
  77.     num = -1;
  78.     type = rpack(&len,&num,data);    /* Try to read a packet. */
  79.  
  80.     chkint();            /* Look for interruptions. */
  81.  
  82.     if ( window ) {
  83.         rpktno = num;        /* Set the packet num just received  */
  84.         if ( type == 'T') {         /* Timeout for window, set number    */
  85.          type =  'N';           /* to most desirable and set type=N  */
  86.          rpktno = wndesr();
  87.         }
  88.         if ( type == 'Q' || type == 'N') {       /* Bad checksum or NACK */
  89.          if ( type == 'N' ) numtry++;        /* NACK increment retry */
  90.          type = 'N';             /* We either want to send a NACK or */
  91.         }                 /* treat it like we received a NACK */
  92.         else numtry = 0;
  93.  
  94.         return(type);
  95.  
  96.     } else {
  97.  
  98. /* Not in window state     */
  99.  
  100. /* If it's the same packet we just sent, it's an echo.  Read another. */
  101.  
  102.        if (type == sndtyp)     type = rpack(&len,&num,data);
  103.  
  104.  
  105. /*
  106.  If previous packet again, a timeout pseudopacket, or a bad packet, try again.
  107. */
  108.         if ( type == 'E') return(type);
  109.  
  110.         if (num != pktnum || type == 'T' || type == 'Q' || type == 'N') {
  111.            numtry++;
  112.            resend();           /*  send last packet again, */
  113.         } else {
  114.         numtry = 0;
  115.         rpktno = num;
  116.         return(type); }        /*  Success, return packet type. */
  117.     }
  118.      }
  119.  
  120. /* Too many tries, give up, and send a timeout error packet  */
  121.  
  122.       errpkt("Other side timed out.");
  123.       strcpy(data,"Timed out.");
  124.       return('E');
  125. }
  126.  
  127. /* G W D A T A --  Receive data in a sliding window */
  128.  
  129. gwdata() {
  130.  
  131.      int wndtop;
  132.  
  133.      wndtop = (wndlow +  2 * (wndsiz) -1 ) % 64; /* Maximum receive window */
  134.      if (wndtop == wndlow ) wndtop = ( wndtop + 1) %  64;
  135.      if ( ckintv(&rpktno,&wndlow,&wndhgh) ) {
  136.            pktnum = rpktno;         /* Packet inside send */
  137.            wndack[rpktno] = 1;        /* window, ACK it and mark  */
  138.            wndtry[rpktno] = 0;        /* as such  */
  139.            ack();
  140.            strcpy(wndata[rpktno],data);    /* Store the packet     */
  141.  
  142. /* ============================================================================
  143. /* Check to see if we are filling window, if so test for skipped packages */
  144.  
  145.            if ( ckintv(&pktexp,&wndlow,&wndhgh))  {
  146.           for (i = pktexp; i != rpktno; i = ( i + 1) % 64 ) {
  147.              if ( wndack[i] || wndtry[i] ) break;
  148.              pktnum = i;          /* See if we lost some   */
  149.              nack();              /* if so, NACK it */
  150.           }
  151.           pktexp = (pktexp + 1) % 64;
  152.            }
  153.  
  154. =========================================================================== */
  155.      } else if ( ckintv(&rpktno,&wndhgh,&wndtop) ) {
  156.            pktnum = rpktno;            /* Received is greater then */
  157.            ack();                   /* send window. */
  158.            strcpy(wndata[rpktno],data);    /* Store the packet    */
  159.            wndack[rpktno] = 1;           /* mark as ACK and    */
  160.            while ( 1 ) {               /* Slide the window    */
  161.           if ( wndack[wndlow] != 1 ) return(0); /* Protocol error  */
  162.           decode(wndata[wndlow],putfil);  /* Decode and store low  */
  163.           wndack[wndlow] = 0;          /* packet & clear ackflg */
  164.           wndlow = (wndlow + 1) % 64;      /* Up lower bound  */
  165.           wndhgh = (wndhgh + 1) % 64;      /* Up higher bound */
  166.           if ( wndhgh == rpktno ) break;  /* End of sliding  */
  167.           pktnum = wndhgh;          /* Nack any packets that */
  168.           nack();              /* have been lost */
  169.           wndack[pktnum] = 0;
  170.           wndtry[pktnum] = 1;
  171.            }
  172.       }
  173. /* Anything else ignore  */
  174.  
  175.       return(1);
  176. }
  177.  
  178. /* R W E O F --  Received EOF in sliding window, write the window to disk */
  179.  
  180.  
  181. rweof() {                    /* Received EOF  */
  182.                         /* Write ACKed packages */
  183.       while ( wndack[wndlow] )
  184.           {
  185.         decode(wndata[wndlow],putfil);    /* Decode and store low packet*/
  186.         wndack[wndlow] = 0;        /* clear ackflg */
  187.         wndlow = (wndlow + 1) % 64;    /* Up lower bound */
  188.           }
  189.  
  190. }
  191.  
  192. /* N A C K D P    -- Bad data packet in window, try to NACK it.    */
  193. /*           Returns 0, if timeout */
  194.  
  195. nackdp() {
  196.  
  197. int wndtop;
  198.  
  199. /* Packets with BAD checksum or timeout,  NACK the appropiate one */
  200.  
  201.  
  202.        wndtop = ( wndhgh + 1 ) % 64;       /* Highest we are allowed to Nack */
  203.        if ( ckintv(&rpktno,&wndlow,&wndtop) ) { /* Packet inside window, */
  204.        if ( wndack[rpktno] ) {        /* already ACKed */
  205.         pktnum = wndesr();        /* NACK, desirable one    */
  206.        } else {                /* else, NACK received packet */
  207.         pktnum = rpktno;        /* Up retry limit & test */
  208.         if ( wndtry[rpktno]++ > MAXTRY ) return(0); }
  209.     } else {
  210.        pktnum = wndesr();            /* Get most desirable packet */
  211.     }
  212.     nack();                 /* NACK pktnum */
  213.     return(1);                /* Succesfully NACKed */
  214. }
  215.  
  216. /*  S D A T A W -- Send the next data packet in sliding window */
  217. /*           Return 0 if EOF */
  218.  
  219. sdataw()  {
  220.  
  221. /*  received an ACK to a data package */
  222.  
  223. /* ACK inside window, mark it as ACKed */
  224.  
  225.       if ( ckintv(&rpktno,&wndlow,&pktnum) ) wndack[rpktno] = 1;
  226.  
  227.       while ( wndack[wndlow] )  {         /* Slide window in send table */
  228.         wndtry[wndlow] = 0;
  229.         wndack[wndlow] = 0;
  230.         wndlow = (wndlow + 1) % 64;
  231.         wndhgh = (wndhgh + 1) % 64;
  232.           }
  233.       while (1) {
  234.           if ( cxseen || czseen ) return(0);       /* Aborted */
  235.           else if ( pktnum == wndhgh ) return(1);       /* Window is full */
  236.           else if ( !sdata()) {               /* End of file    */
  237.            if ( wndtry[wndlow] == 0 ) window = 0;  /* Window is empty */
  238.            return(0);
  239.           }
  240.           strcpy(wndata[pktnum],sndpkt);           /* Store data in  */
  241.           wndack[pktnum] = 0;               /* window  */
  242.           wndtry[pktnum] = 1;
  243.           if ( ttsome() )  return(1);           /* Some waiting */
  244.       }
  245. }
  246.  
  247. /* W R E S N D    --  Resend the requested data packet from the window */
  248. /*            Returns 0 if timeout */
  249.  
  250. wresnd()  {
  251.  
  252. /*  resend  data packet rpktno */
  253.  
  254.                           /* NACK inside window */
  255.     if ( ckintv(&rpktno,&wndlow,&pktnum) ) {
  256.  
  257.         if ( wndtry[rpktno] != 0 ) {      /* Did we ever send it */
  258.  
  259.            if ( wndtry[rpktno]++ > MAXTRY )  return(0); /* Up & test retry */
  260.  
  261.            ttol(wndata[rpktno],strlen(wndata[rpktno])); /* Resend it */
  262.  
  263.                          /* Display that resend occurred */
  264.            screen(SCR_PT,'%',(long)rpktno,wndata[rpktno]);
  265.                          /* Log packet if desired */
  266.  
  267.            if (pktlog && *sndpkt) zsoutl(ZPFILE,wndata[rpktno]);
  268.          }
  269.     }
  270. /*  Keep on sending data packets if we didn't receive something and the
  271.     window is not filled */
  272.  
  273.         while (1) {
  274.           if ( ttsome() || pktnum == wndhgh )  return(1);
  275.  
  276.           if ( !sdata())  return(1);           /* End of file     */
  277.           strcpy(wndata[pktnum],sndpkt);           /* Store data in  */
  278.           wndack[pktnum] = 0;               /* window  */
  279.           wndtry[pktnum] = 1;
  280.         }
  281. }
  282.  
  283. /*  W E O F  --  Receive ACK to data package, while there is no more data */
  284. /*         to send, return 1 if all packets have been ACKed      */
  285.  
  286. weof() {
  287.  
  288. /*  received an ACK to a data package */
  289.  
  290.                            /* ACK inside window */
  291.  
  292.     if ( ckintv(&rpktno,&wndlow,&wndhgh) ) wndack[rpktno] = 1;
  293.     while ( wndack[wndlow] ) {
  294.          if ( wndlow == pktnum ) return(1);  /* All packets ACKed ? */
  295.          wndack[wndlow] = 0;         /* No, slide low end of */
  296.          wndlow = (wndlow + 1) % 64;     /* window */
  297.     }
  298.     return(0);
  299. }
  300.  
  301. /* W D I N I T       initialize windowing variables */
  302. /*           returns 1 if windows are requested */
  303.  
  304. wdinit() {
  305.  
  306.     int i;
  307.  
  308.       if ( !sldwnd || wndsiz == 0) return(0);
  309.       window = 1;
  310.       for (i = 0; i < 64; i++ ) {
  311.           wndack[i] = 0;
  312.           wndtry[i] = 0;
  313.           wndata[i][0] = '\0';
  314.       }
  315.       wndlow = pktnum;
  316.       wndhgh = (pktnum + wndsiz - 1 ) % 64;
  317.       return(1);
  318. }
  319.  
  320.  
  321. /*  W N D E S R   returns most desirable packet  */
  322.  
  323. int wndesr() {
  324.  
  325.       int i;
  326.  
  327.       i = wndlow;
  328.       while (1) {
  329.         if ( !wndack[i] ) return(i);
  330.         if ( i == wndhgh) break;
  331.         i = ( i + 1 ) % 64;
  332.       }
  333.       i = ( i + 1 ) % 64;
  334.       return ( i );
  335.  }
  336.  
  337. /*  C K I N T V  --  check to see if a value is within an interval */
  338. /*             Return 1 if within interval */
  339.  
  340. /*    a is reference value */
  341. /*    b = lower bound of interval ( b >= 0 ) */
  342. /*    c = higher bound of interval ( c >= 0 ) */
  343.  
  344. int ckintv(a,b,c) int *a, *b, *c; {
  345.  
  346.      if ( *a < 0 || *a > 63 ) return(0);
  347.      else if ( *b > *c ) {              /*     Split interval       */
  348.          if ( *a > *c && *a < *b ) return(0); /*|=======c-------b=======| */
  349.          else return(1);              /*<-- a -->        <-- a --> */
  350.  
  351.      } else {                  /*  Continuous interval     */
  352.          if ( *a < *b || *a > *c ) return(0); /*|-------b=======c-------| */
  353.          else return(1);              /*        <-- a -->          */
  354.      }
  355. }
  356.  
  357. /* W N D E R R    -- Abort while in windowing state */
  358. /*           Print error messages d      */
  359.  
  360. wnderr(d) char *d; {
  361.       int x;
  362.  
  363.        ermsg(d);             /* Issue message */
  364.        errpkt(d);             /* Send the other side the message */
  365.        x = quiet;
  366.        quiet = 1;
  367.        cxseen = 1;             /* We aborted */
  368.        clsif(); clsof();         /* Close files and window */
  369.        quiet = x;
  370. }
  371.  
  372.