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