1/*
2 * Copyright (c) 1988, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#if 0
31#ifndef lint
32static const char sccsid[] = "@(#)ring.c	8.2 (Berkeley) 5/30/95";
33#endif
34#endif
35
36/*
37 * This defines a structure for a ring buffer.
38 *
39 * The circular buffer has two parts:
40 *(((
41 *	full:	[consume, supply)
42 *	empty:	[supply, consume)
43 *]]]
44 *
45 */
46
47#include	<errno.h>
48#include	<stdio.h>
49#include	<string.h>
50
51#ifdef	size_t
52#undef	size_t
53#endif
54
55#include	<sys/types.h>
56#ifndef	FILIO_H
57#include	<sys/ioctl.h>
58#endif
59#include	<sys/socket.h>
60
61#include	"ring.h"
62#include	"general.h"
63
64/* Internal macros */
65
66#if	!defined(MIN)
67#define	MIN(a,b)	(((a)<(b))? (a):(b))
68#endif	/* !defined(MIN) */
69
70#define	ring_subtract(d,a,b)	(((a)-(b) >= 0)? \
71					(a)-(b): (((a)-(b))+(d)->size))
72
73#define	ring_increment(d,a,c)	(((a)+(c) < (d)->top)? \
74					(a)+(c) : (((a)+(c))-(d)->size))
75
76#define	ring_decrement(d,a,c)	(((a)-(c) >= (d)->bottom)? \
77					(a)-(c) : (((a)-(c))-(d)->size))
78
79
80/*
81 * The following is a clock, used to determine full, empty, etc.
82 *
83 * There is some trickiness here.  Since the ring buffers are initialized
84 * to ZERO on allocation, we need to make sure, when interpreting the
85 * clock, that when the times are EQUAL, then the buffer is FULL.
86 */
87static u_long ring_clock = 0;
88
89
90#define	ring_empty(d) (((d)->consume == (d)->supply) && \
91				((d)->consumetime >= (d)->supplytime))
92#define	ring_full(d) (((d)->supply == (d)->consume) && \
93				((d)->supplytime > (d)->consumetime))
94
95/* Buffer state transition routines */
96
97int
98ring_init(Ring *ring, unsigned char *buffer, int count)
99{
100    memset((char *)ring, 0, sizeof *ring);
101
102    ring->size = count;
103
104    ring->supply = ring->consume = ring->bottom = buffer;
105
106    ring->top = ring->bottom+ring->size;
107
108#ifdef	ENCRYPTION
109    ring->clearto = 0;
110#endif	/* ENCRYPTION */
111
112    return 1;
113}
114
115/* Mark routines */
116
117/*
118 * Mark the most recently supplied byte.
119 */
120
121void
122ring_mark(Ring *ring)
123{
124    ring->mark = ring_decrement(ring, ring->supply, 1);
125}
126
127/*
128 * Is the ring pointing to the mark?
129 */
130
131int
132ring_at_mark(Ring *ring)
133{
134    if (ring->mark == ring->consume) {
135	return 1;
136    } else {
137	return 0;
138    }
139}
140
141/*
142 * Clear any mark set on the ring.
143 */
144
145void
146ring_clear_mark(Ring *ring)
147{
148    ring->mark = 0;
149}
150
151/*
152 * Add characters from current segment to ring buffer.
153 */
154void
155ring_supplied(Ring *ring, int count)
156{
157    ring->supply = ring_increment(ring, ring->supply, count);
158    ring->supplytime = ++ring_clock;
159}
160
161/*
162 * We have just consumed "c" bytes.
163 */
164void
165ring_consumed(Ring *ring, int count)
166{
167    if (count == 0)	/* don't update anything */
168	return;
169
170    if (ring->mark &&
171		(ring_subtract(ring, ring->mark, ring->consume) < count)) {
172	ring->mark = 0;
173    }
174#ifdef	ENCRYPTION
175    if (ring->consume < ring->clearto &&
176		ring->clearto <= ring->consume + count)
177	ring->clearto = 0;
178    else if (ring->consume + count > ring->top &&
179		ring->bottom <= ring->clearto &&
180		ring->bottom + ((ring->consume + count) - ring->top))
181	ring->clearto = 0;
182#endif	/* ENCRYPTION */
183    ring->consume = ring_increment(ring, ring->consume, count);
184    ring->consumetime = ++ring_clock;
185    /*
186     * Try to encourage "ring_empty_consecutive()" to be large.
187     */
188    if (ring_empty(ring)) {
189	ring->consume = ring->supply = ring->bottom;
190    }
191}
192
193
194
195/* Buffer state query routines */
196
197
198/* Number of bytes that may be supplied */
199int
200ring_empty_count(Ring *ring)
201{
202    if (ring_empty(ring)) {	/* if empty */
203	    return ring->size;
204    } else {
205	return ring_subtract(ring, ring->consume, ring->supply);
206    }
207}
208
209/* number of CONSECUTIVE bytes that may be supplied */
210int
211ring_empty_consecutive(Ring *ring)
212{
213    if ((ring->consume < ring->supply) || ring_empty(ring)) {
214			    /*
215			     * if consume is "below" supply, or empty, then
216			     * return distance to the top
217			     */
218	return ring_subtract(ring, ring->top, ring->supply);
219    } else {
220				    /*
221				     * else, return what we may.
222				     */
223	return ring_subtract(ring, ring->consume, ring->supply);
224    }
225}
226
227/* Return the number of bytes that are available for consuming
228 * (but don't give more than enough to get to cross over set mark)
229 */
230
231int
232ring_full_count(Ring *ring)
233{
234    if ((ring->mark == 0) || (ring->mark == ring->consume)) {
235	if (ring_full(ring)) {
236	    return ring->size;	/* nothing consumed, but full */
237	} else {
238	    return ring_subtract(ring, ring->supply, ring->consume);
239	}
240    } else {
241	return ring_subtract(ring, ring->mark, ring->consume);
242    }
243}
244
245/*
246 * Return the number of CONSECUTIVE bytes available for consuming.
247 * However, don't return more than enough to cross over set mark.
248 */
249int
250ring_full_consecutive(Ring *ring)
251{
252    if ((ring->mark == 0) || (ring->mark == ring->consume)) {
253	if ((ring->supply < ring->consume) || ring_full(ring)) {
254	    return ring_subtract(ring, ring->top, ring->consume);
255	} else {
256	    return ring_subtract(ring, ring->supply, ring->consume);
257	}
258    } else {
259	if (ring->mark < ring->consume) {
260	    return ring_subtract(ring, ring->top, ring->consume);
261	} else {	/* Else, distance to mark */
262	    return ring_subtract(ring, ring->mark, ring->consume);
263	}
264    }
265}
266
267/*
268 * Move data into the "supply" portion of of the ring buffer.
269 */
270void
271ring_supply_data(Ring *ring, unsigned char *buffer, int count)
272{
273    int i;
274
275    while (count) {
276	i = MIN(count, ring_empty_consecutive(ring));
277	memcpy(ring->supply, buffer, i);
278	ring_supplied(ring, i);
279	count -= i;
280	buffer += i;
281    }
282}
283
284#ifdef	ENCRYPTION
285void
286ring_encrypt(Ring *ring, void (*encryptor)(unsigned char *, int))
287{
288    unsigned char *s, *c;
289
290    if (ring_empty(ring) || ring->clearto == ring->supply)
291	return;
292
293    if (!(c = ring->clearto))
294	c = ring->consume;
295
296    s = ring->supply;
297
298    if (s <= c) {
299	(*encryptor)(c, ring->top - c);
300	(*encryptor)(ring->bottom, s - ring->bottom);
301    } else
302	(*encryptor)(c, s - c);
303
304    ring->clearto = ring->supply;
305}
306
307void
308ring_clearto(Ring *ring)
309{
310    if (!ring_empty(ring))
311	ring->clearto = ring->supply;
312    else
313	ring->clearto = 0;
314}
315#endif	/* ENCRYPTION */
316