xref: /original-bsd/usr.bin/telnet/ring.c (revision de436421)
1 /*
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)ring.c	8.2 (Berkeley) 05/30/95";
10 #endif /* not lint */
11 
12 /*
13  * This defines a structure for a ring buffer.
14  *
15  * The circular buffer has two parts:
16  *(((
17  *	full:	[consume, supply)
18  *	empty:	[supply, consume)
19  *]]]
20  *
21  */
22 
23 #include	<stdio.h>
24 #include	<errno.h>
25 
26 #ifdef	size_t
27 #undef	size_t
28 #endif
29 
30 #include	<sys/types.h>
31 #ifndef	FILIO_H
32 #include	<sys/ioctl.h>
33 #endif
34 #include	<sys/socket.h>
35 
36 #include	"ring.h"
37 #include	"general.h"
38 
39 /* Internal macros */
40 
41 #if	!defined(MIN)
42 #define	MIN(a,b)	(((a)<(b))? (a):(b))
43 #endif	/* !defined(MIN) */
44 
45 #define	ring_subtract(d,a,b)	(((a)-(b) >= 0)? \
46 					(a)-(b): (((a)-(b))+(d)->size))
47 
48 #define	ring_increment(d,a,c)	(((a)+(c) < (d)->top)? \
49 					(a)+(c) : (((a)+(c))-(d)->size))
50 
51 #define	ring_decrement(d,a,c)	(((a)-(c) >= (d)->bottom)? \
52 					(a)-(c) : (((a)-(c))-(d)->size))
53 
54 
55 /*
56  * The following is a clock, used to determine full, empty, etc.
57  *
58  * There is some trickiness here.  Since the ring buffers are initialized
59  * to ZERO on allocation, we need to make sure, when interpreting the
60  * clock, that when the times are EQUAL, then the buffer is FULL.
61  */
62 static u_long ring_clock = 0;
63 
64 
65 #define	ring_empty(d) (((d)->consume == (d)->supply) && \
66 				((d)->consumetime >= (d)->supplytime))
67 #define	ring_full(d) (((d)->supply == (d)->consume) && \
68 				((d)->supplytime > (d)->consumetime))
69 
70 
71 
72 
73 
74 /* Buffer state transition routines */
75 
76     ring_init(ring, buffer, count)
77 Ring *ring;
78     unsigned char *buffer;
79     int count;
80 {
81     memset((char *)ring, 0, sizeof *ring);
82 
83     ring->size = count;
84 
85     ring->supply = ring->consume = ring->bottom = buffer;
86 
87     ring->top = ring->bottom+ring->size;
88 
89 #ifdef	ENCRYPTION
90     ring->clearto = 0;
91 #endif	/* ENCRYPTION */
92 
93     return 1;
94 }
95 
96 /* Mark routines */
97 
98 /*
99  * Mark the most recently supplied byte.
100  */
101 
102     void
103 ring_mark(ring)
104     Ring *ring;
105 {
106     ring->mark = ring_decrement(ring, ring->supply, 1);
107 }
108 
109 /*
110  * Is the ring pointing to the mark?
111  */
112 
113     int
114 ring_at_mark(ring)
115     Ring *ring;
116 {
117     if (ring->mark == ring->consume) {
118 	return 1;
119     } else {
120 	return 0;
121     }
122 }
123 
124 /*
125  * Clear any mark set on the ring.
126  */
127 
128     void
129 ring_clear_mark(ring)
130     Ring *ring;
131 {
132     ring->mark = 0;
133 }
134 
135 /*
136  * Add characters from current segment to ring buffer.
137  */
138     void
139 ring_supplied(ring, count)
140     Ring *ring;
141     int count;
142 {
143     ring->supply = ring_increment(ring, ring->supply, count);
144     ring->supplytime = ++ring_clock;
145 }
146 
147 /*
148  * We have just consumed "c" bytes.
149  */
150     void
151 ring_consumed(ring, count)
152     Ring *ring;
153     int count;
154 {
155     if (count == 0)	/* don't update anything */
156 	return;
157 
158     if (ring->mark &&
159 		(ring_subtract(ring, ring->mark, ring->consume) < count)) {
160 	ring->mark = 0;
161     }
162 #ifdef	ENCRYPTION
163     if (ring->consume < ring->clearto &&
164 		ring->clearto <= ring->consume + count)
165 	ring->clearto = 0;
166     else if (ring->consume + count > ring->top &&
167 		ring->bottom <= ring->clearto &&
168 		ring->bottom + ((ring->consume + count) - ring->top))
169 	ring->clearto = 0;
170 #endif	/* ENCRYPTION */
171     ring->consume = ring_increment(ring, ring->consume, count);
172     ring->consumetime = ++ring_clock;
173     /*
174      * Try to encourage "ring_empty_consecutive()" to be large.
175      */
176     if (ring_empty(ring)) {
177 	ring->consume = ring->supply = ring->bottom;
178     }
179 }
180 
181 
182 
183 /* Buffer state query routines */
184 
185 
186 /* Number of bytes that may be supplied */
187     int
188 ring_empty_count(ring)
189     Ring *ring;
190 {
191     if (ring_empty(ring)) {	/* if empty */
192 	    return ring->size;
193     } else {
194 	return ring_subtract(ring, ring->consume, ring->supply);
195     }
196 }
197 
198 /* number of CONSECUTIVE bytes that may be supplied */
199     int
200 ring_empty_consecutive(ring)
201     Ring *ring;
202 {
203     if ((ring->consume < ring->supply) || ring_empty(ring)) {
204 			    /*
205 			     * if consume is "below" supply, or empty, then
206 			     * return distance to the top
207 			     */
208 	return ring_subtract(ring, ring->top, ring->supply);
209     } else {
210 				    /*
211 				     * else, return what we may.
212 				     */
213 	return ring_subtract(ring, ring->consume, ring->supply);
214     }
215 }
216 
217 /* Return the number of bytes that are available for consuming
218  * (but don't give more than enough to get to cross over set mark)
219  */
220 
221     int
222 ring_full_count(ring)
223     Ring *ring;
224 {
225     if ((ring->mark == 0) || (ring->mark == ring->consume)) {
226 	if (ring_full(ring)) {
227 	    return ring->size;	/* nothing consumed, but full */
228 	} else {
229 	    return ring_subtract(ring, ring->supply, ring->consume);
230 	}
231     } else {
232 	return ring_subtract(ring, ring->mark, ring->consume);
233     }
234 }
235 
236 /*
237  * Return the number of CONSECUTIVE bytes available for consuming.
238  * However, don't return more than enough to cross over set mark.
239  */
240     int
241 ring_full_consecutive(ring)
242     Ring *ring;
243 {
244     if ((ring->mark == 0) || (ring->mark == ring->consume)) {
245 	if ((ring->supply < ring->consume) || ring_full(ring)) {
246 	    return ring_subtract(ring, ring->top, ring->consume);
247 	} else {
248 	    return ring_subtract(ring, ring->supply, ring->consume);
249 	}
250     } else {
251 	if (ring->mark < ring->consume) {
252 	    return ring_subtract(ring, ring->top, ring->consume);
253 	} else {	/* Else, distance to mark */
254 	    return ring_subtract(ring, ring->mark, ring->consume);
255 	}
256     }
257 }
258 
259 /*
260  * Move data into the "supply" portion of of the ring buffer.
261  */
262     void
263 ring_supply_data(ring, buffer, count)
264     Ring *ring;
265     unsigned char *buffer;
266     int count;
267 {
268     int i;
269 
270     while (count) {
271 	i = MIN(count, ring_empty_consecutive(ring));
272 	memmove(ring->supply, buffer, i);
273 	ring_supplied(ring, i);
274 	count -= i;
275 	buffer += i;
276     }
277 }
278 
279 #ifdef notdef
280 
281 /*
282  * Move data from the "consume" portion of the ring buffer
283  */
284     void
285 ring_consume_data(ring, buffer, count)
286     Ring *ring;
287     unsigned char *buffer;
288     int count;
289 {
290     int i;
291 
292     while (count) {
293 	i = MIN(count, ring_full_consecutive(ring));
294 	memmove(buffer, ring->consume, i);
295 	ring_consumed(ring, i);
296 	count -= i;
297 	buffer += i;
298     }
299 }
300 #endif
301 
302 #ifdef	ENCRYPTION
303     void
304 ring_encrypt(ring, encryptor)
305     Ring *ring;
306     void (*encryptor)();
307 {
308     unsigned char *s, *c;
309 
310     if (ring_empty(ring) || ring->clearto == ring->supply)
311 	return;
312 
313     if (!(c = ring->clearto))
314 	c = ring->consume;
315 
316     s = ring->supply;
317 
318     if (s <= c) {
319 	(*encryptor)(c, ring->top - c);
320 	(*encryptor)(ring->bottom, s - ring->bottom);
321     } else
322 	(*encryptor)(c, s - c);
323 
324     ring->clearto = ring->supply;
325 }
326 
327     void
328 ring_clearto(ring)
329     Ring *ring;
330 {
331     if (!ring_empty(ring))
332 	ring->clearto = ring->supply;
333     else
334 	ring->clearto = 0;
335 }
336 #endif	/* ENCRYPTION */
337