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