xref: /csrg-svn/usr.bin/telnet/ring.c (revision 69785)
132379Sminshall /*
262311Sbostic  * Copyright (c) 1988, 1993
362311Sbostic  *	The Regents of the University of California.  All rights reserved.
433685Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
633685Sbostic  */
733685Sbostic 
833685Sbostic #ifndef lint
9*69785Sdab static char sccsid[] = "@(#)ring.c	8.2 (Berkeley) 05/30/95";
1033685Sbostic #endif /* not lint */
1133685Sbostic 
1233685Sbostic /*
1332528Sminshall  * This defines a structure for a ring buffer.
1432379Sminshall  *
1532528Sminshall  * The circular buffer has two parts:
1632379Sminshall  *(((
1732528Sminshall  *	full:	[consume, supply)
1832528Sminshall  *	empty:	[supply, consume)
1932379Sminshall  *]]]
2032379Sminshall  *
2132379Sminshall  */
2232379Sminshall 
2332379Sminshall #include	<stdio.h>
2432379Sminshall #include	<errno.h>
2532379Sminshall 
2632379Sminshall #ifdef	size_t
2732379Sminshall #undef	size_t
2832379Sminshall #endif
2932379Sminshall 
3032379Sminshall #include	<sys/types.h>
3144360Sborman #ifndef	FILIO_H
3232379Sminshall #include	<sys/ioctl.h>
3344360Sborman #endif
3432379Sminshall #include	<sys/socket.h>
3532379Sminshall 
3632379Sminshall #include	"ring.h"
3732379Sminshall #include	"general.h"
3832379Sminshall 
3932379Sminshall /* Internal macros */
4032379Sminshall 
4132381Sminshall #if	!defined(MIN)
4232381Sminshall #define	MIN(a,b)	(((a)<(b))? (a):(b))
4332381Sminshall #endif	/* !defined(MIN) */
4432379Sminshall 
4538689Sborman #define	ring_subtract(d,a,b)	(((a)-(b) >= 0)? \
4632381Sminshall 					(a)-(b): (((a)-(b))+(d)->size))
4732379Sminshall 
4832379Sminshall #define	ring_increment(d,a,c)	(((a)+(c) < (d)->top)? \
4932379Sminshall 					(a)+(c) : (((a)+(c))-(d)->size))
5032379Sminshall 
5133294Sminshall #define	ring_decrement(d,a,c)	(((a)-(c) >= (d)->bottom)? \
5233294Sminshall 					(a)-(c) : (((a)-(c))-(d)->size))
5332379Sminshall 
5433294Sminshall 
5532379Sminshall /*
5632379Sminshall  * The following is a clock, used to determine full, empty, etc.
5732379Sminshall  *
5832379Sminshall  * There is some trickiness here.  Since the ring buffers are initialized
5932379Sminshall  * to ZERO on allocation, we need to make sure, when interpreting the
6032528Sminshall  * clock, that when the times are EQUAL, then the buffer is FULL.
6132379Sminshall  */
6232379Sminshall static u_long ring_clock = 0;
6332379Sminshall 
6432379Sminshall 
6532528Sminshall #define	ring_empty(d) (((d)->consume == (d)->supply) && \
6632528Sminshall 				((d)->consumetime >= (d)->supplytime))
6732528Sminshall #define	ring_full(d) (((d)->supply == (d)->consume) && \
6832528Sminshall 				((d)->supplytime > (d)->consumetime))
6932379Sminshall 
7032379Sminshall 
7132379Sminshall 
7232379Sminshall 
7332379Sminshall 
7432379Sminshall /* Buffer state transition routines */
7532379Sminshall 
ring_init(ring,buffer,count)7646808Sdab     ring_init(ring, buffer, count)
7732381Sminshall Ring *ring;
7846808Sdab     unsigned char *buffer;
7946808Sdab     int count;
8032381Sminshall {
8132381Sminshall     memset((char *)ring, 0, sizeof *ring);
8232379Sminshall 
8332381Sminshall     ring->size = count;
8432381Sminshall 
8532528Sminshall     ring->supply = ring->consume = ring->bottom = buffer;
8632381Sminshall 
8732381Sminshall     ring->top = ring->bottom+ring->size;
8832381Sminshall 
8960149Sdab #ifdef	ENCRYPTION
9046808Sdab     ring->clearto = 0;
9160149Sdab #endif	/* ENCRYPTION */
9246808Sdab 
9332381Sminshall     return 1;
9432381Sminshall }
9532381Sminshall 
9633294Sminshall /* Mark routines */
9733294Sminshall 
9832379Sminshall /*
9933294Sminshall  * Mark the most recently supplied byte.
10033294Sminshall  */
10133294Sminshall 
10246808Sdab     void
ring_mark(ring)10333294Sminshall ring_mark(ring)
10446808Sdab     Ring *ring;
10533294Sminshall {
10633294Sminshall     ring->mark = ring_decrement(ring, ring->supply, 1);
10733294Sminshall }
10833294Sminshall 
10933294Sminshall /*
11033294Sminshall  * Is the ring pointing to the mark?
11133294Sminshall  */
11233294Sminshall 
11346808Sdab     int
ring_at_mark(ring)11433294Sminshall ring_at_mark(ring)
11546808Sdab     Ring *ring;
11633294Sminshall {
11733294Sminshall     if (ring->mark == ring->consume) {
11833294Sminshall 	return 1;
11933294Sminshall     } else {
12033294Sminshall 	return 0;
12133294Sminshall     }
12233294Sminshall }
12333294Sminshall 
12433294Sminshall /*
12533294Sminshall  * Clear any mark set on the ring.
12633294Sminshall  */
12733294Sminshall 
12846808Sdab     void
ring_clear_mark(ring)12933294Sminshall ring_clear_mark(ring)
13046808Sdab     Ring *ring;
13133294Sminshall {
13233294Sminshall     ring->mark = 0;
13333294Sminshall }
13433294Sminshall 
13533294Sminshall /*
13632379Sminshall  * Add characters from current segment to ring buffer.
13732379Sminshall  */
13846808Sdab     void
ring_supplied(ring,count)13932528Sminshall ring_supplied(ring, count)
14046808Sdab     Ring *ring;
14146808Sdab     int count;
14232379Sminshall {
14332528Sminshall     ring->supply = ring_increment(ring, ring->supply, count);
14432528Sminshall     ring->supplytime = ++ring_clock;
14532379Sminshall }
14632379Sminshall 
14732379Sminshall /*
14832528Sminshall  * We have just consumed "c" bytes.
14932379Sminshall  */
15046808Sdab     void
ring_consumed(ring,count)15132528Sminshall ring_consumed(ring, count)
15246808Sdab     Ring *ring;
15346808Sdab     int count;
15432379Sminshall {
15532667Sminshall     if (count == 0)	/* don't update anything */
15632667Sminshall 	return;
15732667Sminshall 
15833294Sminshall     if (ring->mark &&
15933294Sminshall 		(ring_subtract(ring, ring->mark, ring->consume) < count)) {
16033294Sminshall 	ring->mark = 0;
16133294Sminshall     }
16260149Sdab #ifdef	ENCRYPTION
16346808Sdab     if (ring->consume < ring->clearto &&
16446808Sdab 		ring->clearto <= ring->consume + count)
16546808Sdab 	ring->clearto = 0;
16646808Sdab     else if (ring->consume + count > ring->top &&
16746808Sdab 		ring->bottom <= ring->clearto &&
16846808Sdab 		ring->bottom + ((ring->consume + count) - ring->top))
16946808Sdab 	ring->clearto = 0;
17060149Sdab #endif	/* ENCRYPTION */
17132528Sminshall     ring->consume = ring_increment(ring, ring->consume, count);
17232528Sminshall     ring->consumetime = ++ring_clock;
17332547Sminshall     /*
17432547Sminshall      * Try to encourage "ring_empty_consecutive()" to be large.
17532547Sminshall      */
17632547Sminshall     if (ring_empty(ring)) {
17732547Sminshall 	ring->consume = ring->supply = ring->bottom;
17832547Sminshall     }
17932379Sminshall }
18032379Sminshall 
18132379Sminshall 
18232379Sminshall 
18332379Sminshall /* Buffer state query routines */
18432379Sminshall 
18532379Sminshall 
18632528Sminshall /* Number of bytes that may be supplied */
18746808Sdab     int
ring_empty_count(ring)18832379Sminshall ring_empty_count(ring)
18946808Sdab     Ring *ring;
19032379Sminshall {
19132528Sminshall     if (ring_empty(ring)) {	/* if empty */
19232379Sminshall 	    return ring->size;
19332379Sminshall     } else {
19432528Sminshall 	return ring_subtract(ring, ring->consume, ring->supply);
19532379Sminshall     }
19632379Sminshall }
19732379Sminshall 
19832528Sminshall /* number of CONSECUTIVE bytes that may be supplied */
19946808Sdab     int
ring_empty_consecutive(ring)20032379Sminshall ring_empty_consecutive(ring)
20146808Sdab     Ring *ring;
20232379Sminshall {
20332528Sminshall     if ((ring->consume < ring->supply) || ring_empty(ring)) {
20432528Sminshall 			    /*
20532528Sminshall 			     * if consume is "below" supply, or empty, then
20632528Sminshall 			     * return distance to the top
20732528Sminshall 			     */
20832528Sminshall 	return ring_subtract(ring, ring->top, ring->supply);
20932379Sminshall     } else {
21032379Sminshall 				    /*
21132379Sminshall 				     * else, return what we may.
21232379Sminshall 				     */
21332528Sminshall 	return ring_subtract(ring, ring->consume, ring->supply);
21432379Sminshall     }
21532379Sminshall }
21632379Sminshall 
21733294Sminshall /* Return the number of bytes that are available for consuming
21833294Sminshall  * (but don't give more than enough to get to cross over set mark)
21933294Sminshall  */
22033294Sminshall 
22146808Sdab     int
ring_full_count(ring)22232528Sminshall ring_full_count(ring)
22346808Sdab     Ring *ring;
22432379Sminshall {
22533294Sminshall     if ((ring->mark == 0) || (ring->mark == ring->consume)) {
22633294Sminshall 	if (ring_full(ring)) {
22733294Sminshall 	    return ring->size;	/* nothing consumed, but full */
22833294Sminshall 	} else {
22933294Sminshall 	    return ring_subtract(ring, ring->supply, ring->consume);
23033294Sminshall 	}
23132379Sminshall     } else {
23233294Sminshall 	return ring_subtract(ring, ring->mark, ring->consume);
23332379Sminshall     }
23432379Sminshall }
23532379Sminshall 
23633294Sminshall /*
23733294Sminshall  * Return the number of CONSECUTIVE bytes available for consuming.
23833294Sminshall  * However, don't return more than enough to cross over set mark.
23933294Sminshall  */
24046808Sdab     int
ring_full_consecutive(ring)24132528Sminshall ring_full_consecutive(ring)
24246808Sdab     Ring *ring;
24332379Sminshall {
24433294Sminshall     if ((ring->mark == 0) || (ring->mark == ring->consume)) {
24533294Sminshall 	if ((ring->supply < ring->consume) || ring_full(ring)) {
24633294Sminshall 	    return ring_subtract(ring, ring->top, ring->consume);
24733294Sminshall 	} else {
24833294Sminshall 	    return ring_subtract(ring, ring->supply, ring->consume);
24933294Sminshall 	}
25032379Sminshall     } else {
25133294Sminshall 	if (ring->mark < ring->consume) {
25233294Sminshall 	    return ring_subtract(ring, ring->top, ring->consume);
25333294Sminshall 	} else {	/* Else, distance to mark */
25433294Sminshall 	    return ring_subtract(ring, ring->mark, ring->consume);
25533294Sminshall 	}
25632379Sminshall     }
25732379Sminshall }
25832379Sminshall 
25932379Sminshall /*
26032528Sminshall  * Move data into the "supply" portion of of the ring buffer.
26132379Sminshall  */
26246808Sdab     void
ring_supply_data(ring,buffer,count)26332528Sminshall ring_supply_data(ring, buffer, count)
26446808Sdab     Ring *ring;
26546808Sdab     unsigned char *buffer;
26646808Sdab     int count;
26732379Sminshall {
26832379Sminshall     int i;
26932379Sminshall 
27032379Sminshall     while (count) {
27132381Sminshall 	i = MIN(count, ring_empty_consecutive(ring));
272*69785Sdab 	memmove(ring->supply, buffer, i);
27332528Sminshall 	ring_supplied(ring, i);
27432379Sminshall 	count -= i;
27532379Sminshall 	buffer += i;
27632379Sminshall     }
27732379Sminshall }
27832379Sminshall 
27944360Sborman #ifdef notdef
28032379Sminshall 
28132379Sminshall /*
28232528Sminshall  * Move data from the "consume" portion of the ring buffer
28332379Sminshall  */
28446808Sdab     void
ring_consume_data(ring,buffer,count)28532528Sminshall ring_consume_data(ring, buffer, count)
28646808Sdab     Ring *ring;
28746808Sdab     unsigned char *buffer;
28846808Sdab     int count;
28932379Sminshall {
29032379Sminshall     int i;
29132379Sminshall 
29232379Sminshall     while (count) {
29332528Sminshall 	i = MIN(count, ring_full_consecutive(ring));
294*69785Sdab 	memmove(buffer, ring->consume, i);
29532528Sminshall 	ring_consumed(ring, i);
29632379Sminshall 	count -= i;
29732379Sminshall 	buffer += i;
29832379Sminshall     }
29932379Sminshall }
30044360Sborman #endif
30146808Sdab 
30260149Sdab #ifdef	ENCRYPTION
30346808Sdab     void
ring_encrypt(ring,encryptor)30446808Sdab ring_encrypt(ring, encryptor)
30546808Sdab     Ring *ring;
30646808Sdab     void (*encryptor)();
30746808Sdab {
30846808Sdab     unsigned char *s, *c;
30946808Sdab 
31046808Sdab     if (ring_empty(ring) || ring->clearto == ring->supply)
31146808Sdab 	return;
31246808Sdab 
31346808Sdab     if (!(c = ring->clearto))
31446808Sdab 	c = ring->consume;
31546808Sdab 
31646808Sdab     s = ring->supply;
31746808Sdab 
31846808Sdab     if (s <= c) {
31946808Sdab 	(*encryptor)(c, ring->top - c);
32046808Sdab 	(*encryptor)(ring->bottom, s - ring->bottom);
32146808Sdab     } else
32246808Sdab 	(*encryptor)(c, s - c);
32346808Sdab 
32446808Sdab     ring->clearto = ring->supply;
32546808Sdab }
32646808Sdab 
32746808Sdab     void
ring_clearto(ring)32846808Sdab ring_clearto(ring)
32946808Sdab     Ring *ring;
33046808Sdab {
33146808Sdab     if (!ring_empty(ring))
33246808Sdab 	ring->clearto = ring->supply;
33346808Sdab     else
33446808Sdab 	ring->clearto = 0;
33546808Sdab }
33660149Sdab #endif	/* ENCRYPTION */
337