home *** CD-ROM | disk | FTP | other *** search
- /*
- For best results in visual layout while viewing this file, set
- tab stops to every 4 columns.
- */
-
- /*
- dcpgpkt.c
-
- Revised edition of dcp
-
- Stuart Lynne May/87
-
- Copyright (c) Richard H. Lamb 1985, 1986, 1987
- Changes Copyright (c) Stuart Lynne 1987
-
- Maintenance notes:
-
- 25Aug87 - Allow for up to 7 windows - Jal
- 01Nov87 - those strncpy's should really be memcpy's! - Jal
- 11Sep89 - Raise TimeOut to 15 - ahd
- 30Apr90 - Add Jordon Brown's fix for short packet retries.
- Reduce retry limit to 20 ahd
- 22Jul90 - Change error retry limit from per host to per
- packet. ahd
- 22Jul90 - Add error message for number of retries exceeded ahd
- 08Sep90 - Drop memmove to memcpy change supplied by Jordan
- Brown, MS 6.0 and Turbo C++ agree memmove insures
- no overlap
- */
-
- /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
-
- /* 7-window "g" ptotocol */
-
- /*
- Thanks goes to John Gilmore for sending me a copy of Greg Chesson's
- UUCP protocol description -- Obviously invaluable.
- Thanks also go to Andrew Tannenbaum for the section on Siding window
- protocols with a program example in his "Computer Networks" book.
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
-
- #include "lib.h"
- #include "dcp.h"
- #include "dcpsys.h"
- #include "dcpgpkt.h"
- #include "hostable.h"
- #include "security.h"
- #include "ulib.h"
- #include "modem.h"
-
- #define PKTSIZE 64
- #define PKTSIZ2 2 /* 8x(2**2) = 64 */
-
- #define HDRSIZE 6
- #define MAXTRY 4
-
- /*--------------------------------------------------------------------*/
- /* g-packet type definitions */
- /*--------------------------------------------------------------------*/
-
- #define DATA 0
- #define CLOSE 1
- #define NAK 2
- #define SRJ 3
- #define ACK 4
- #define INITC 5
- #define INITB 6
- #define INITA 7
-
- #define POK -1
-
- #define MAXWINDOW 7
- #define NBUF 8 /* always SAME as MAXSEQ ? */
- #define MAXSEQ 8
-
- #define between(a,b,c) ((a<=b && b<c) || \
- (c<a && a<=b) || \
- (b<c && c<a))
-
- #define nextpkt(x) ((x + 1) % MAXSEQ)
-
- /*--------------------------------------------------------------------*/
- /* Global variables for packet definitions */
- /*--------------------------------------------------------------------*/
-
- static int rwl, swl, swu, rwu, nbuffers, irec, lazynak;
- static INTEGER nerr;
- static int outlen[NBUF], inlen[NBUF], arrived[NBUF];
- static int nwindows, maxwindows;
- static char outbuf[NBUF][PKTSIZE+1], inbuf[NBUF][PKTSIZE+1];
- static long ftimer[NBUF];
- static int timeouts, outsequence, naksin, naksout, screwups;
- static int reinit, shifts, badhdr, resends;
-
- /*--------------------------------------------------------------------*/
- /* Internal function prototypes */
- /*--------------------------------------------------------------------*/
-
- static int gmachine(const int timeout);
- static void gspack(int type,int yyy,int xxx,int len,char *data);
- static int grpack(int *yyy,
- int *xxx,
- int *len,
- char *data,
- const int timeout);
- static void gstats( void );
-
- static unsigned int checksum(char *data, int len);
-
- /****************** SUB SUB SUB PACKET HANDLER ************/
-
- /*
- g o p e n p k
- */
-
- int gopenpk()
- {
- int i, xxx, yyy, len;
- char tmp[PKTSIZE+1];
-
- pktsize = PKTSIZE; /* change it later after the init */
- maxwindows = GetGWindow( MAXWINDOW );
-
- /*--------------------------------------------------------------------*/
- /* Initialize error counters */
- /*--------------------------------------------------------------------*/
-
- timeouts = outsequence = naksin = naksout = screwups =
- shifts = badhdr = resends = reinit = 0;
-
- /*--------------------------------------------------------------------*/
- /* Initialize proto parameters */
- /*--------------------------------------------------------------------*/
-
- nerr = nbuffers = 0;
- swl = swu = 1;
- rwl = 0;
- nwindows = maxwindows;
- rwu = nwindows - 1;
- if ( PortTimeout == 0 )
- PortTimeout = PacketTimeout * 2 - 1;
- for (i = 0; i < NBUF; i++) {
- ftimer[i] = 0;
- arrived[i] = FALSE;
- }
-
- /*--------------------------------------------------------------------*/
- /* 3-way handshake */
- /*--------------------------------------------------------------------*/
-
- gspack(INITA, 0, 0, 0, tmp);
- rsrt:
- if (nerr >= MaxErr)
- {
- remote_stats.errors += nerr;
- nerr = 0;
- printmsg(0,
- "gopenpk: Consecutive error limit of %ld exceeded, %ld total errors",
- (long) MaxErr, remote_stats.errors);
- return(FAILED);
- }
-
- /*--------------------------------------------------------------------*/
- /* INIT sequence. Easy fix for variable packet size. I didn't */
- /* since all the machines I talk to use PKTSZ=64. If you do */
- /* this make sure to reflect the changes in "grpack" and */
- /* "gspack" */
- /*--------------------------------------------------------------------*/
-
- switch (grpack(&yyy, &xxx, &len, tmp, PacketTimeout )) {
- case INITA:
- printmsg(5, "**got INITA");
- nwindows = yyy;
- if (nwindows > maxwindows)
- nwindows = maxwindows;
- rwu = nwindows - 1;
- gspack(INITB, 0, 0, 0, tmp); /* data segment (packet) size */
- goto rsrt;
- case INITB:
- printmsg(5, "**got INITB");
- gspack(INITC, 0, 0, 0, tmp);
- goto rsrt;
- case INITC:
- printmsg(5, "**got INITC");
- break;
- default:
- nerr++;
- screwups++;
- printmsg(5, "**got SCREW UP");
- gspack(INITA, 0, 0, 0, tmp);
- goto rsrt;
- }
-
- nerr = 0;
- lazynak = 0;
- return(OK); /* channel open */
-
- } /*gopenpk*/
-
- /*--------------------------------------------------------------------*/
- /* g f i l e p k t */
- /* */
- /* Begin a file transfer (not used by "g" protocol) */
- /*--------------------------------------------------------------------*/
-
- int gfilepkt( void )
- {
- return OK;
- } /* gfilepkt */
-
- /*--------------------------------------------------------------------*/
- /* g c l o s e p k */
- /* */
- /* Close packet machine */
- /*--------------------------------------------------------------------*/
-
- int gclosepk()
- {
- int i;
- char tmp[PKTSIZE+1];
-
- for (i = 0; i < MAXTRY; i++) {
- gspack(CLOSE, 0, 0, 0, tmp);
- if (gmachine(PacketTimeout) == CLOSE)
- break;
- }
-
- gstats();
- return(0);
-
- } /*gclosepk*/
-
- /*--------------------------------------------------------------------*/
- /* g s t a t s */
- /* */
- /* Report summary of errors for processing */
- /*--------------------------------------------------------------------*/
-
- static void gstats( void )
- {
- remote_stats.errors += nerr;
- nerr = 0;
- if ( remote_stats.errors || shifts || badhdr )
- {
- printmsg(0,
- "%d time outs, %d port reinits, %d out of seq pkts, \
- %d NAKs rec, %d NAKs sent",
- timeouts, reinit, outsequence, naksin, naksout);
- printmsg(0,
- "%d invalid pkt types, %d re-syncs, %d bad pkt hdrs, %d pkts resent",
- screwups, shifts, badhdr, resends);
- }
- }
-
- /*
- g g e t p k t
-
- Gets no more than a packet's worth of data from
- the "packet I/O state machine". May have to
- periodically run the packet machine to get some packets.
-
- on input: don't care
- on return: data+\0 and length in len.
-
- ret(0) if all's well
- ret(-1) if problems (failed)
- */
-
- int ggetpkt(char *data, int *len)
- {
- int i;
- int retry = MaxErr;
- time_t start;
- #ifdef _DEBUG
- int savedebug = debuglevel;
- #endif
-
- irec = 1;
- time( &start );
-
- /*--------------------------------------------------------------------*/
- /* Loop to wait for the desired packet */
- /*--------------------------------------------------------------------*/
-
- while (!arrived[rwl] && retry)
- {
- if (gmachine(PacketTimeout) != POK)
- return(-1);
-
- if (!arrived[rwl] )
- {
- time_t now;
- if (time( &now ) > (start + PacketTimeout) )
- {
- #ifdef _DEBUG
- if ( debuglevel < 6 )
- debuglevel = 6;
- #endif
- printmsg(5,"ggetpkt: Timeout %d waiting for inbound packet %d",
- MaxErr - --retry, remote_stats.packets + 1);
- timeouts++;
- start = now;
- } /* if (time( now ) > (start + PacketTimeout) ) */
- } /* if (!arrived[rwl] ) */
- } /* while (!arrived[rwl] && i) */
-
- #ifdef _DEBUG
- debuglevel = savedebug;
- #endif
-
- if (!arrived[rwl])
- {
- printmsg(0,"ggetpkt: Remote host failed to respond after %ld seconds",
- (long) PacketTimeout * MaxErr);
- gclosepk();
- return -1;
- }
-
- /*--------------------------------------------------------------------*/
- /* Got a packet! */
- /*--------------------------------------------------------------------*/
-
- i = rwl; /*<-- mod(,rwindow) for larger than 8 seq no.s */
- *len = inlen[i];
- memcpy(data, inbuf[i], *len);
-
- arrived[i] = FALSE;
- rwu = nextpkt(rwu) ; /* bump receive window */
-
- return(0);
-
- } /*ggetpkt*/
-
-
- /*
- g s e n d p k t
-
- Put at most a packet's worth of data in the packet state
- machine for transmission.
- May have to run the packet machine a few times to get
- an available output slot.
-
- on input: data=*data; len=length of data in data.
-
- return:
- 0 if all's well
- -1 if problems (failed)
- */
-
- int gsendpkt(char *data, int len)
- {
- int i1;
- #ifdef _DEBUG
- int savedebug = debuglevel;
- #endif
-
- irec = 0;
- /* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been
- acked, wait for acks */
- while (nbuffers >= nwindows)
- if (gmachine(0) != POK) /* Spin with no timeout */
- return(-1);
-
- i1 = swu; /* <--If we ever have more than 8 seq no.s, must mod() here */
-
- /*--------------------------------------------------------------------*/
- /* Place packet in table and mark unacked */
- /*--------------------------------------------------------------------*/
-
- memcpy(outbuf[i1], data, len);
-
- /*--------------------------------------------------------------------*/
- /* Handle short packets. */
- /*--------------------------------------------------------------------*/
-
- if(len < PKTSIZE) {
- memmove(outbuf[i1] + 1, outbuf[i1], PKTSIZE - 1);
- outbuf[i1][0] = (unsigned char) (PKTSIZE - len);
- memset(outbuf[i1]+len+1, 0, PKTSIZE-len-1);
- /* Pad with nulls. Ugh. */
- }
-
- /*--------------------------------------------------------------------*/
- /* Mark packet */
- /*--------------------------------------------------------------------*/
-
- outlen[i1] = len;
- ftimer[i1] = time(nil(long));
- swu = nextpkt(swu); /* bump send window */
- nbuffers++;
-
- /*--------------------------------------------------------------------*/
- /* send it */
- /*--------------------------------------------------------------------*/
-
- gspack(DATA, rwl, i1, outlen[i1], outbuf[i1]);
-
- #ifdef _DEBUG
- debuglevel = savedebug;
- #endif
-
- return(0);
-
- } /*gsendpkt*/
-
-
- /*--------------------------------------------------------------------*/
- /* g e o f p k t */
- /* */
- /* Transmit EOF to the other system */
- /*--------------------------------------------------------------------*/
-
- int geofpkt( void )
- {
- char outbuf[PKTSIZE+1];
- if (gsendpkt(outbuf, 0)) /* Empty packet == EOF */
- return FAILED;
- else
- return OK;
- } /* geofpkt */
-
- /*--------------------------------------------------------------------*/
- /* g w r m s g */
- /* */
- /* Send a message to remote system */
- /*--------------------------------------------------------------------*/
-
- int gwrmsg( char *s )
- {
- for(; strlen(s) >= pktsize; s += pktsize) {
- int result = gsendpkt(s, pktsize);
- if (result)
- return result;
- }
-
- return gsendpkt(s, strlen(s)+1);
- } /* gwrmsg */
-
- /*--------------------------------------------------------------------*/
- /* g r d m s g */
- /* */
- /* Read a message from the remote system */
- /*--------------------------------------------------------------------*/
-
- int grdmsg( char *s)
- {
- for ( ;; )
- {
- int len;
- int result = ggetpkt( s, &len );
- if (result || (s[len-1] == '\0'))
- return result;
- s += len;
- } /* for */
-
- } /* grdmsg */
-
- /********** Packet Machine ********** RH Lamb 3/87 */
-
- /*--------------------------------------------------------------------*/
- /* g m a c h i n e */
- /* */
- /* Ideally we would like to fork this process off in an */
- /* infinite loop and send and receive packets through "inbuf" */
- /* and "outbuf". Can't do this in MS-DOS so we setup "getpkt" */
- /* and "sendpkt" to call this routine often and return only */
- /* when the input buffer is empty thus "blocking" the packet- */
- /* machine task. */
- /*--------------------------------------------------------------------*/
-
- static int gmachine(const int timeout )
- {
- static time_t idletimer = 0;
- static time_t acktimer = 0;
-
- boolean done = FALSE; /* True = drop out of machine loop */
- boolean close = FALSE; /* True = terminate connection upon
- exit */
- boolean inseq = TRUE; /* True = Count next out of sequence
- packet as an error */
- char rdata[PKTSIZE+1];
-
- while ( !done )
- {
- boolean resend = FALSE; /* True = resend data packets */
- boolean donak = FALSE; /* True = NAK the other system */
- unsigned long packet_no = remote_stats.packets;
-
- int pkttype, rack, rseq, rlen, i1;
- time_t now;
-
- if ( debuglevel >= 7 ) /* Optimize processing a little bit */
- {
- printmsg(10, "* send %d < W < %d, receive %d < W < %d, error %d",
- swl, swu, rwl, rwu, nerr);
-
- /*--------------------------------------------------------------------*/
- /* Waiting for ACKs for swl to swu-1. Next pkt to send=swu */
- /* rwl=expected pkt */
- /*--------------------------------------------------------------------*/
-
- printmsg(7, "Bytes transfered %ld errors %d",
- (long) (remote_stats.packets * PKTSIZE) , nerr);
- }
-
- /*--------------------------------------------------------------------*/
- /* Attempt to retrieve a packet and handle it */
- /*--------------------------------------------------------------------*/
-
- pkttype = grpack(&rack, &rseq, &rlen, rdata, timeout);
- time(&now);
- switch (pkttype) {
-
- case CLOSE:
- remote_stats.packets++;
- printmsg(5, "**got CLOSE");
- close = done = TRUE;
- break;
-
- case EMPTY:
- printmsg(6, "**got EMPTY");
- if (acktimer && (acktimer <= (now - PortTimeout)))
- {
- printmsg(5,"*** port re-init");
- reinit++;
- flowcontrol( FALSE );
- acktimer = now;
- }
-
- if (ftimer[swl])
- {
- printmsg(6, "---> seq, elapst %d %ld", swl,
- ftimer[swl] - now);
- if ( ftimer[swl] <= (now - PacketTimeout))
- {
- printmsg(4, "*** timeout %d (%ld)",
- swl, (long) remote_stats.packets);
- /* Since "g" is "go-back-N", when we time out we
- must send the last N pkts in order. The generalized
- sliding window scheme relaxes this reqirment. */
- nerr++;
- timeouts++;
- resend = TRUE;
- } /* if */
- } /* if */
- else if (now > (idletimer + PacketTimeout))
- printmsg(2,"*** BORED");
-
- done = TRUE;
- break;
-
- case DATA:
- printmsg(5, "**got DATA %d %d", rack, rseq);
- i1 = nextpkt(rwl); /* (R+1)%8 <-- -->(R+W)%8 */
- if (i1 == rseq) {
- lazynak--;
- remote_stats.packets++;
- idletimer = now;
- inseq = arrived[i1] = TRUE;
- inlen[i1] = rlen;
- memcpy(inbuf[i1], rdata, rlen);
- rwl = i1;
- printmsg(5, "*** ACK d %d", rwl);
- gspack(ACK, rwl, 0, 0, rdata);
- done = TRUE; /* return to caller when finished */
- /* in a mtask system, unneccesary */
- } else {
- if (inseq || ( now > (idletimer + PacketTimeout)))
- {
- donak = TRUE; /* Only flag first out of sequence
- packet as error, since we know
- following ones also bad */
- outsequence++;
- inseq = FALSE;
- }
- printmsg(5, "*** unexpect %d ne %d (%d - %d)",
- rseq, i1, rwl, rwu);
- } /* else */
-
- if ( swl == swu ) /* We waiting for an ACK? */
- break; /* No --> Skip ACK processing */
- /* else Fall through to ACK case */
-
- case NAK:
- case ACK:
- if (pkttype == NAK)
- {
- nerr++;
- naksin++;
- printmsg(5, "**got NAK %d", rack);
- resend = TRUE;
- }
- else if (pkttype == ACK)
- printmsg(5, "**got ACK %d", rack);
- acktimer = now;
-
- while(between(swl, rack, swu))
- { /* S<-- -->(S+W-1)%8 */
- remote_stats.packets++;
- printmsg(5, "*** ACK %d", swl);
- ftimer[swl] = 0;
- idletimer = acktimer;
- nbuffers--;
- done = TRUE; /* Get more data for input */
- swl = nextpkt(swl);
- } /* while */
-
- if (!done && (pkttype == ACK)) /* Find packet? */
- {
- printmsg(0,"*** ACK for bad packet %d (%d - %d)",
- rack, swl, swu);
- } /* if */
- break;
-
- case ERROR:
- printmsg(5, "*** got BAD CHK");
- acktimer = now;
- naksout++;
- donak = TRUE;
- lazynak = 0; /* Always NAK bad checksum */
- break;
-
- default:
- screwups++;
- nerr++;
- printmsg(5, "*** got SCREW UP");
- break;
-
- } /* switch */
-
- /*--------------------------------------------------------------------*/
- /* If we received an NAK or timed out, resend data packets */
- /*--------------------------------------------------------------------*/
-
- if ( resend )
- for (rack = swl; between(swl, rack, swu); rack = nextpkt(rack))
- { /* resend rack->(swu-1) */
- resends++;
- gspack(DATA, rwl, rack, outlen[rack], outbuf[rack]);
- printmsg(5, "*** resent %d", rack);
- idletimer = ftimer[rack] = now;
- } /* for */
-
- /*--------------------------------------------------------------------*/
- /* If we have an error and have not recently sent a NAK, do so now. */
- /* We then reset our counter so we receive at least a window full of */
- /* packets before sending another NAK */
- /*--------------------------------------------------------------------*/
-
- if ( donak )
- {
- nerr++;
- if ( (lazynak < 1) || (now > (idletimer + PacketTimeout)))
- {
- printmsg(5, "*** NAK d %d", rwl);
- gspack(NAK, rwl, 0, 0, rdata);
- naksout++;
- idletimer = now;
- lazynak = nwindows + 1;
- } /* if ( lazynak < 1 ) */
- } /* if ( donak ) */
-
- /*--------------------------------------------------------------------*/
- /* Update error counter if needed */
- /*--------------------------------------------------------------------*/
-
- if ((close || (packet_no != remote_stats.packets)) && (nerr > 0))
- {
- printmsg(2,"gmachine: Packet %ld had %ld errors during transfer",
- remote_stats.packets, (long) nerr);
- remote_stats.errors += nerr;
- nerr = 0;
- }
-
- /*--------------------------------------------------------------------*/
- /* If we have an excessive number of errors, drop out of the */
- /* loop */
- /*--------------------------------------------------------------------*/
-
- if (nerr >= MaxErr)
- {
- printmsg(0,
- "gmachine: Consecutive error limit of %d exceeded, %d total errors",
- MaxErr, nerr + remote_stats.errors);
- done = close = TRUE;
- gstats();
- }
- } /* while */
-
- /*--------------------------------------------------------------------*/
- /* Return to caller, gracefully terminating packet machine if */
- /* requested */
- /*--------------------------------------------------------------------*/
-
- if ( close )
- {
- gspack(CLOSE, 0, 0, 0, rdata);
- return CLOSE;
- }
- else
- return POK;
-
- } /*gmachine*/
-
-
- /*************** FRAMING *****************************/
-
- /*
- g s p a c k
-
- Send a packet
-
- type=type yyy=pkrec xxx=timesent len=length<=PKTSIZE data=*data
- ret(0) always
- */
-
- static void gspack(int type, int yyy, int xxx, int len, char *data)
- {
- unsigned int check, i;
- unsigned char header[HDRSIZE];
-
- #ifdef LINKTEST
- /***** Link Testing Mods *****/
- unsigned char dpkerr[10];
- /***** End Link Testing Mods *****/
- #endif /* LINKTEST */
-
- #ifdef LINKTEST
- /***** Link Testing Mods - create artificial errors *****/
- printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
- gets(dpkerr);
- if (dpkerr[0] == 's')
- sscanf(&dpkerr[1], "%d", &xxx);
- /***** End Link Testing Mods *****/
- #endif /* LINKTEST */
-
- printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d",
- type, yyy, xxx, len);
- header[0] = '\020';
- type %= 8;
- header[4] = (unsigned char) (type << 3);
- switch (type) {
- case CLOSE:
- break; /* stop protocol */
- case NAK:
- header[4] += yyy;
- break; /* reject */
- case SRJ:
- break;
- case ACK:
- header[4] += yyy;
- break; /* ack */
- case INITC:
- header[4] += nwindows;
- break;
- case INITB:
- header[4] += 1;
- break; /* pktsiz = 64 (1) */
- case INITA:
- header[4] += maxwindows;
- break;
- case DATA:
- header[4] = (unsigned char) (0x80 + (xxx << 3) + yyy);
- /* havn't set it up for VERY LONG packets with a few
- bytes yet (-128) */
- if (len < PKTSIZE) { /* short packet? */
- header[4] |= 0x40;
- printmsg(7, "data=|%.*s|", len+1, data);
- /* Count byte is handled at a higher level. */
- /* Header construction should probably be handled there too. */
- } else printmsg(7, "data=|%.*s|", len, data);
- break;
- }
- if (type != DATA) {
- header[1] = 9; /* control packet size = 0 (9) */
- check = (0xaaaa - header[4]) & 0xffff;
- } else {
- header[1] = PKTSIZ2; /* data packet size = 64 (2) */
- check = checksum(data, PKTSIZE);
- i = header[4]; /* got to do this on PC for ex-or high bits */
- i &= 0xff;
- check = (check ^ i) & 0xffff;
- check = (0xaaaa - check) & 0xffff;
- }
- header[2] = (unsigned char) (check & 0xff);
- header[3] = (unsigned char) ((check >> 8) & 0xff);
- header[5] = (unsigned char)
- ((header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff) ;
-
- #ifdef LINKTEST
- /***** More Link Testing Mods *****/
- switch(dpkerr[0]) {
- case 'e':
- data[10] = - data[10];
- break;
- case 'h':
- header[5] = - header[5];
- break;
- case 'l':
- return;
- case 'p':
- swrite((char *) header, HDRSIZE);
- if (header[1] != 9)
- swrite(data, PKTSIZE - 3);
- return;
- default:
- break;
- }
- /***** End Link Testing Mods *****/
- #endif /* LINKTEST */
-
- swrite((char *) header, HDRSIZE); /* header is 6-bytes long */
- if (header[1] != 9)
- swrite(data, PKTSIZE); /* data is always 64 bytes long */
-
- } /*gspack*/
-
-
- /*
- g r p a c k
-
- Read packet
-
- on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE data=*data
-
- ret(type) ok
- ret(EMPTY) input buf empty
- ret(ERROR) bad header
-
- ret(EMPTY) lost packet timeout
- ret(ERROR) checksum error
- ret(-5) packet size != 64
-
- NOTE (specifications for sread()):
-
- sread(buf, n, timeout)
- while(TRUE) {
- if (# of chars available >= n) (without dec internal counter)
- read n chars into buf (decrement internal char counter)
- break
- else
- if (time > timeout)
- break;
- }
- return(# of chars available)
-
- */
-
- static int grpack(int *yyy, int *xxx, int *len, char *data, const int timeout)
- {
- static int got_hdr = FALSE;
- static unsigned char grpkt[PKTSIZE+HDRSIZE];
- static int received = 0; /* Bytes already read into buffer */
- int needed;
-
- unsigned int type, check, checkchk, i, total;
- unsigned char c, c2;
-
- time_t start;
-
- if (got_hdr)
- goto get_data;
-
- /*--------------------------------------------------------------------*/
- /* Spin up to timeout waiting for a Control-P, our sync character */
- /*--------------------------------------------------------------------*/
-
- start = 0;
- while (!got_hdr)
- {
- unsigned char *psync;
-
- needed = HDRSIZE - received;
- if ( needed > 0 ) /* Have enough bytes for header? */
- { /* No --> Read as much as we need */
- int wait;
-
- if ( start == 0 ) /* First pass through data? */
- { /* Yes --> Set timers up */
- start = time(nil(time_t));
- wait = timeout;
- } /* if ( start == 0 ) */
- else {
- wait = (int) (time(NULL) - start) - timeout;
- if (wait < 0) /* Negative timeout? */
- wait = 0; /* Make it no time out */
- } /* else */
-
- if (sread((char *) &grpkt[received], needed, wait ) < (unsigned) needed )
- /* Did we get the needed data? */
- return EMPTY; /* No --> Return to caller */
- received += needed;
- } /* if ( needed < received ) */
-
- /*--------------------------------------------------------------------*/
- /* Search for sync character in newly read data */
- /*--------------------------------------------------------------------*/
-
- printmsg(10,"grpack: Have %d characters after reading %d",
- received, needed);
- psync = memchr( grpkt, '\020', received );
- if ( psync == NULL ) /* Did we find the sync character? */
- received = 0; /* No --> Reset to empty buffer */
- else if ( psync != grpkt ) /* First character in buffer? */
- { /* No --> Make it first character */
- received -= psync - grpkt;
- shifts++;
- memmove( grpkt, psync, received );
- /* Shift buffer over */
- } /* else */
-
- /*--------------------------------------------------------------------*/
- /* If we have read an entire packet header, then perform a */
- /* simple XOR checksum to determine if it is valid. If we have */
- /* a valid checksum, drop out of this search, else drop the */
- /* sync character and restart the scan. */
- /*--------------------------------------------------------------------*/
-
- if ( received >= HDRSIZE )
- {
- i = (unsigned) (grpkt[1] ^ grpkt[2] ^ grpkt[3] ^
- grpkt[4] ^ grpkt[5]);
- i &= 0xff;
- printmsg(i ? 2 : 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
- grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
-
- if (i == 0) /* Good header? */
- got_hdr = TRUE; /* Yes --> Drop out of loop */
- else { /* No --> Flag it, continue loop */
- badhdr++;
- printmsg(2, "*** bad pkt header ***");
- memmove( grpkt, &grpkt[ 1 ], --received );
- /* Begin scanning for sync character
- with next byte */
- } /* else */
- } /* if ( received > HDRSIZE ) */
- } /* while */
-
- /*--------------------------------------------------------------------*/
- /* Handle control packets */
- /*--------------------------------------------------------------------*/
-
- if (grpkt[1] == 9)
- {
- *data = '\0';
- *len = 0;
- c = grpkt[4];
- type = c >> 3;
- *yyy = c & 0x07;
- *xxx = 0;
- check = 0;
- checkchk = 0;
- got_hdr = FALSE;
- }
- /*--------------------------------------------------------------------*/
- /* Handle data packets */
- /*--------------------------------------------------------------------*/
- else {
- get_data:
- total = 8 * (2 << grpkt[1]);
- if (total > PKTSIZE)
- {
- printmsg(0,"grpack: Invalid packet size %d (%d)",
- total, (int) grpkt[1]);
- received = 0;
- got_hdr = FALSE;
- return(-5); /* can't handle packet size other than 64 */
- }
-
- needed = total + HDRSIZE - received;
- if ((needed > 0) &&
- (sread(&data[total - needed], needed , timeout) < (unsigned)needed))
- return(EMPTY);
-
- if ( received > HDRSIZE )
- memmove( data, &grpkt[HDRSIZE], received - HDRSIZE);
-
- got_hdr = FALSE;
- type = 0;
- c2 = grpkt[4];
- c = (unsigned char) (c2 & 0x3f);
- *xxx = c >> 3;
- *yyy = c & 0x07;
- i = grpkt[3];
- i = (i << 8) & 0xff00;
- check = grpkt[2];
- check = i | (check & 0xff);
- checkchk = checksum(data, total);
- i = grpkt[4] | 0x80;
- i &= 0xff;
- checkchk = 0xaaaa - (checkchk ^ i);
- checkchk &= 0xffff;
- if (checkchk != check) {
- printmsg(4, "*** checksum error ***");
- memmove( grpkt, data, total );
- /* Save data so we can scan for sync */
- received = total; /* Note the amount of the data in buf */
- return(ERROR); /* Return to caller with error */
- }
- *len = total;
- /* Haven't set it up for very long pkts yet (>128). RH Lamb */
- if (c2 & 0x40) {
- int ii;
- ii = (data[0] & 0xff);
- *len = (*len - ii) & 0xff;
- memmove(data, data + 1, *len);
- }
- } /* else */
-
- /*--------------------------------------------------------------------*/
- /* Announce what we got and return to the caller */
- /*--------------------------------------------------------------------*/
-
- received = 0; /* Returning entire buffer, reset count */
- printmsg(5, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
- type, *yyy, *xxx, *len);
- printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%.*s|",
- check, checkchk, total, data);
-
- return(type);
-
- } /*grpack*/
-
-
- /*
- c h e c k s u m
- */
-
- static unsigned int checksum(char *data, int len)
- {
- int i, j;
- unsigned int tmp, chk1, chk2;
- chk1 = 0xffff;
- chk2 = 0;
- j = len;
- for (i = 0; i < len; i++) {
- if (chk1 & 0x8000) {
- chk1 <<= 1;
- chk1++;
- } else {
- chk1 <<= 1;
- }
- tmp = chk1;
- chk1 += (data[i] & 0xff);
- chk2 += chk1 ^ j;
- if ((chk1 & 0xffff) <= (tmp & 0xffff))
- chk1 ^= chk2;
- j--;
- }
- return(chk1 & 0xffff);
-
- } /*checksum*/
-