home *** CD-ROM | disk | FTP | other *** search
-
- /* C K C F N 3 -- System-independent Kermit protocol support functions... */
-
- /* ...Part 3 (continued from lckfns2.c) */
- /* Protocol functions for sliding window implementation. */
- /*
- Author: Jan A. van der Eyk, NUS Corp., July 1985.
-
- Columbia University Center for Computing Activities, January 1985.
- Copyright (C) 1985, Trustees of Columbia University in the City of New York.
- Permission is granted to any individual or institution to use, copy, or
- redistribute this software so long as it is not sold for profit, provided this
- copyright notice is retained.
- */
- /*
- Note -- if you change this file, please amend the version number and date at
- the top of lckfns.c accordingly.
- */
-
- /* IMPORTANT: When a window is being closed, i.e, after received an end of
- file, pktnum should be reset to the received packet number.
- */
-
-
- #include "lckerm.h"
- #include "lckdeb.h"
-
- int wndack[64], wndtry[64], wndlow, wndhgh, rpktno;
-
- CHAR wndata[64][94];
-
- extern int cxseen, czseen, sndtyp, prvpkt, pktnum, wndsiz, window;
-
- extern int pktlog, sldwnd, quiet;
-
-
- extern int putfil();
-
- extern CHAR data[],sndpkt[], sstate;
-
- CHAR *strcpy();
-
- /* I N P U T -- Attempt to read packet number 'pktnum'. */
-
- /*
- This is the function that feeds input to Kermit's finite state machine.
-
- If a special start state is in effect, that state is returned as if it were
- the type of an incoming packet. Otherwise:
-
- . If the desired packet arrives within MAXTRY tries, return its type,
- with its data stored in the global 'data' array.
-
- . If the previous packet arrives again, resend the last packet and wait for
- another to come in.
-
- . If the desired packet does not arrive within MAXTRY tries, return indicating
- that an error packet should be sent.
- */
-
- input() {
- int len, num, type;
- static int numtry;
-
- if (!window) numtry = 0;
-
- while ( numtry <= MAXTRY )
- {
- if (sstate != 0) { /* If an interrupt routine has set */
- type = sstate; /* sstate behind our back, or */
- sstate = 0; /* if a start state is in effect, */
- *data = '\0'; /* nulify start state and return it */
- numtry = 0; /* like a packet type */
- return(type);
- }
-
- num = -1;
- type = rpack(&len,&num,data); /* Try to read a packet. */
-
- chkint(); /* Look for interruptions. */
-
- if ( window ) {
- rpktno = num; /* Set the packet num just received */
- if ( type == 'T') { /* Timeout for window, set number */
- type = 'N'; /* to most desirable and set type=N */
- rpktno = wndesr();
- }
- if ( type == 'Q' || type == 'N') { /* Bad checksum or NACK */
- if ( type == 'N' ) numtry++; /* NACK increment retry */
- type = 'N'; /* We either want to send a NACK or */
- } /* treat it like we received a NACK */
- else numtry = 0;
-
- return(type);
-
- } else {
-
- /* Not in window state */
-
- /* If it's the same packet we just sent, it's an echo. Read another. */
-
- if (type == sndtyp) type = rpack(&len,&num,data);
-
-
- /*
- If previous packet again, a timeout pseudopacket, or a bad packet, try again.
- */
- if ( type == 'E') return(type);
-
- if (num != pktnum || type == 'T' || type == 'Q' || type == 'N') {
- numtry++;
- resend(); /* send last packet again, */
- } else {
- numtry = 0;
- rpktno = num;
- return(type); } /* Success, return packet type. */
- }
- }
-
- /* Too many tries, give up, and send a timeout error packet */
-
- errpkt("Other side timed out.");
- strcpy(data,"Timed out.");
- return('E');
- }
-
- /* G W D A T A -- Receive data in a sliding window */
-
- gwdata() {
-
- int wndtop;
-
- debug( F101, "Gwdata: received packet", "", rpktno );
- wndtop = (wndlow + 2 * (wndsiz) -1 ) % 64; /* Maximum receive window */
- if (wndtop == wndlow ) wndtop = ( wndtop + 1) % 64;
- if ( ckintv(&rpktno,&wndlow,&wndhgh) ) {
- debug( F100, " Packet is in window\n", "", 0);
- debug( F101, " wndlow", "", wndlow );
- debug( F101, " wndtop", "", wndtop );
- pktnum = rpktno; /* Packet inside send */
- wndack[rpktno] = 1; /* window, ACK it and mark */
- wndtry[rpktno] = 0; /* as such */
- ack();
- strcpy(wndata[rpktno],data); /* Store the packet */
-
- /* ============================================================================
- /* Check to see if we are filling window, if so test for skipped packages **
-
- if ( ckintv(&pktexp,&wndlow,&wndhgh)) {
- for (i = pktexp; i != rpktno; i = ( i + 1) % 64 ) {
- if ( wndack[i] || wndtry[i] ) break;
- pktnum = i; /* See if we lost some **
- nack(); /* if so, NACK it **
- }
- pktexp = (pktexp + 1) % 64;
- }
-
- =========================================================================== */
- } else if ( ckintv(&rpktno,&wndhgh,&wndtop) ) {
- debug( F100, " Packet is outside window\n", "", 0);
- pktnum = rpktno; /* Received is greater then */
- ack(); /* send window. */
- strcpy(wndata[rpktno],data); /* Store the packet */
- wndack[rpktno] = 1; /* mark as ACK and */
- while ( 1 ) { /* Slide the window */
- if ( wndack[wndlow] != 1 ) return(0); /* Protocol error */
- decode(wndata[wndlow],putfil); /* Decode and store low */
- wndack[wndlow] = 0; /* packet & clear ackflg */
- wndlow = (wndlow + 1) % 64; /* Up lower bound */
- wndhgh = (wndhgh + 1) % 64; /* Up higher bound */
- if ( wndhgh == rpktno ) break; /* End of sliding */
- pktnum = wndhgh; /* Nack any packets that */
- nack(); /* have been lost */
- wndack[pktnum] = 0;
- wndtry[pktnum] = 1;
- }
- debug( F101, " wndlow", "", wndlow );
- debug( F101, " wndtop", "", wndtop );
-
- }
- /* Anything else ignore */
-
- return(1);
- }
-
- /* R W E O F -- Received EOF in sliding window, write the window to disk */
-
-
- rweof() { /* Received EOF */
- /* Write ACKed packages */
- while ( wndack[wndlow] )
- {
- decode(wndata[wndlow],putfil); /* Decode and store low packet*/
- wndack[wndlow] = 0; /* clear ackflg */
- wndlow = (wndlow + 1) % 64; /* Up lower bound */
- }
-
- }
-
- /* N A C K D P -- Bad data packet in window, try to NACK it. */
- /* Returns 0, if timeout */
-
- nackdp() {
-
- int wndtop;
-
- /* Packets with BAD checksum or timeout, NACK the appropiate one */
-
- wndtop = ( wndhgh + 1 ) % 64; /* Highest we are allowed to Nack */
- if ( ckintv(&rpktno,&wndlow,&wndtop) ) { /* Packet inside window, */
- if ( wndack[rpktno] ) { /* already ACKed */
- pktnum = wndesr(); /* NACK, desirable one */
- } else { /* else, NACK received packet */
- pktnum = rpktno; /* Up retry limit & test */
- if ( wndtry[rpktno]++ > MAXTRY ) return(0); }
- } else {
- pktnum = wndesr(); /* Get most desirable packet */
- }
- debug( F101, "Nacking packet #", "", rpktno );
- nack(); /* NACK pktnum */
- return(1); /* Succesfully NACKed */
- }
-
- /* S D A T A W -- Send the next data packet in sliding window */
- /* Return 0 if EOF */
-
- sdataw() {
-
- /* received an ACK to a data package */
-
- /* ACK inside window, mark it as ACKed */
-
- if ( ckintv(&rpktno,&wndlow,&pktnum) ) wndack[rpktno] = 1;
-
- while ( wndack[wndlow] ) { /* Slide window in send table */
- wndtry[wndlow] = 0;
- wndack[wndlow] = 0;
- wndlow = (wndlow + 1) % 64;
- wndhgh = (wndhgh + 1) % 64;
- }
- while (1) {
- if ( cxseen || czseen ) return(0); /* Aborted */
- else if ( pktnum == wndhgh ) return(1); /* Window is full */
- else if ( !sdata()) { /* End of file */
- if ( wndtry[wndlow] == 0 ) window = 0; /* Window is empty */
- return(0);
- }
- strcpy(wndata[pktnum],sndpkt); /* Store data in */
- wndack[pktnum] = 0; /* window */
- wndtry[pktnum] = 1;
- if ( ttsome() ) return(1); /* Some waiting */
- }
- }
-
- /* W R E S N D -- Resend the requested data packet from the window */
- /* Returns 0 if timeout */
-
- wresnd() {
-
- /* resend data packet rpktno */
-
- /* NACK inside window */
- if ( ckintv(&rpktno,&wndlow,&pktnum) ) {
-
- if ( wndtry[rpktno] != 0 ) { /* Did we ever send it */
-
- if ( wndtry[rpktno]++ > MAXTRY ) return(0); /* Up & test retry */
-
- ttol(wndata[rpktno],strlen(wndata[rpktno])); /* Resend it */
-
- /* Display that resend occurred */
- screen(SCR_PT,'%',(long)rpktno,wndata[rpktno]);
- /* Log packet if desired */
-
- if (pktlog && *sndpkt) zsoutl(ZPFILE,wndata[rpktno]);
- }
- }
- /* Keep on sending data packets if we didn't receive something and the
- window is not filled */
-
- while (1) {
- if ( ttsome() || pktnum == wndhgh ) return(1);
-
- if ( !sdata()) return(1); /* End of file */
- strcpy(wndata[pktnum],sndpkt); /* Store data in */
- wndack[pktnum] = 0; /* window */
- wndtry[pktnum] = 1;
- }
- }
-
- /* W E O F -- Receive ACK to data package, while there is no more data */
- /* to send, return 1 if all packets have been ACKed */
-
- weof() {
-
- /* received an ACK to a data package */
-
- /* ACK inside window */
-
- if ( ckintv(&rpktno,&wndlow,&wndhgh) ) wndack[rpktno] = 1;
- while ( wndack[wndlow] ) {
- if ( wndlow == pktnum ) return(1); /* All packets ACKed ? */
- wndack[wndlow] = 0; /* No, slide low end of */
- wndlow = (wndlow + 1) % 64; /* window */
- }
- return(0);
- }
-
- /* W D I N I T initialize windowing variables */
- /* returns 1 if windows are requested */
-
- wdinit() {
-
- int i;
-
- if ( !sldwnd || wndsiz == 0)
- {
- debug(F000,"Sliding Windows not enabled","",0);
- return(0);
- }
- window = 1;
- for (i = 0; i < 64; i++ ) {
- wndack[i] = 0;
- wndtry[i] = 0;
- wndata[i][0] = '\0';
- }
- wndlow = pktnum;
- wndhgh = (pktnum + wndsiz - 1 ) % 64;
- debug(F100, "Wdinit: Initializing window\n", "", 0);
- debug( F101, " wndlow", "", wndlow );
- debug( F101, " wndhgh", "", wndhgh );
- return(1);
- }
-
-
- /* W N D E S R returns most desirable packet */
-
- int wndesr() {
-
- int i;
-
- i = wndlow;
- while (1) {
- if ( !wndack[i] ) return(i);
- if ( i == wndhgh) break;
- i = ( i + 1 ) % 64;
- }
- i = ( i + 1 ) % 64;
- return ( i );
- }
-
- /* C K I N T V -- check to see if a value is within an interval */
- /* Return 1 if within interval */
-
- /* a is reference value */
- /* b = lower bound of interval ( b >= 0 ) */
- /* c = higher bound of interval ( c >= 0 ) */
-
- int ckintv(a,b,c) int *a, *b, *c; {
-
- if ( *a < 0 || *a > 63 ) return(0);
- else if ( *b > *c ) { /* Split interval */
- if ( *a > *c && *a < *b ) return(0); /*|=======c-------b=======| */
- else return(1); /*<-- a --> <-- a --> */
-
- } else { /* Continuous interval */
- if ( *a < *b || *a > *c ) return(0); /*|-------b=======c-------| */
- else return(1); /* <-- a --> */
- }
- }
-
- /* W N D E R R -- Abort while in windowing state */
- /* Print error messages d */
-
- wnderr(d) CHAR *d; {
- int x;
-
- ermsg(d); /* Issue message */
- errpkt(d); /* Send the other side the message */
- x = quiet;
- quiet = 1;
- cxseen = 1; /* We aborted */
- clsif(); clsof(); /* Close files and window */
- quiet = x;
- }
-