Home | History | Annotate | Line # | Download | only in telnet
ring.c revision 1.9
      1 /*	$NetBSD: ring.c,v 1.9 2000/06/22 06:47:48 thorpej 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.9 2000/06/22 06:47:48 thorpej 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 #ifndef NO_STRING_H
     58 #include	<string.h>
     59 #endif
     60 #include	<strings.h>
     61 #include	<errno.h>
     62 
     63 #ifdef	size_t
     64 #undef	size_t
     65 #endif
     66 
     67 #include	<sys/types.h>
     68 #ifndef	FILIO_H
     69 #include	<sys/ioctl.h>
     70 #endif
     71 #include	<sys/socket.h>
     72 
     73 #include	"ring.h"
     74 #include	"general.h"
     75 
     76 /* Internal macros */
     77 
     78 #if	!defined(MIN)
     79 #define	MIN(a,b)	(((a)<(b))? (a):(b))
     80 #endif	/* !defined(MIN) */
     81 
     82 #define	ring_subtract(d,a,b)	(((a)-(b) >= 0)? \
     83 					(a)-(b): (((a)-(b))+(d)->size))
     84 
     85 #define	ring_increment(d,a,c)	(((a)+(c) < (d)->top)? \
     86 					(a)+(c) : (((a)+(c))-(d)->size))
     87 
     88 #define	ring_decrement(d,a,c)	(((a)-(c) >= (d)->bottom)? \
     89 					(a)-(c) : (((a)-(c))-(d)->size))
     90 
     91 
     92 /*
     93  * The following is a clock, used to determine full, empty, etc.
     94  *
     95  * There is some trickiness here.  Since the ring buffers are initialized
     96  * to ZERO on allocation, we need to make sure, when interpreting the
     97  * clock, that when the times are EQUAL, then the buffer is FULL.
     98  */
     99 static u_long ring_clock = 0;
    100 
    101 
    102 #define	ring_empty(d) (((d)->consume == (d)->supply) && \
    103 				((d)->consumetime >= (d)->supplytime))
    104 #define	ring_full(d) (((d)->supply == (d)->consume) && \
    105 				((d)->supplytime > (d)->consumetime))
    106 
    107 
    108 
    109 
    110 
    111 /* Buffer state transition routines */
    112 
    113     int
    114 ring_init(ring, buffer, count)
    115 Ring *ring;
    116     unsigned char *buffer;
    117     int count;
    118 {
    119     memset((char *)ring, 0, sizeof *ring);
    120 
    121     ring->size = count;
    122 
    123     ring->supply = ring->consume = ring->bottom = buffer;
    124 
    125     ring->top = ring->bottom+ring->size;
    126 
    127 #ifdef	ENCRYPTION
    128     ring->clearto = 0;
    129 #endif	/* ENCRYPTION */
    130 
    131     return 1;
    132 }
    133 
    134 /* Mark routines */
    135 
    136 /*
    137  * Mark the most recently supplied byte.
    138  */
    139 
    140     void
    141 ring_mark(ring)
    142     Ring *ring;
    143 {
    144     ring->mark = ring_decrement(ring, ring->supply, 1);
    145 }
    146 
    147 /*
    148  * Is the ring pointing to the mark?
    149  */
    150 
    151     int
    152 ring_at_mark(ring)
    153     Ring *ring;
    154 {
    155     if (ring->mark == ring->consume) {
    156 	return 1;
    157     } else {
    158 	return 0;
    159     }
    160 }
    161 
    162 /*
    163  * Clear any mark set on the ring.
    164  */
    165 
    166     void
    167 ring_clear_mark(ring)
    168     Ring *ring;
    169 {
    170     ring->mark = 0;
    171 }
    172 
    173 /*
    174  * Add characters from current segment to ring buffer.
    175  */
    176     void
    177 ring_supplied(ring, count)
    178     Ring *ring;
    179     int count;
    180 {
    181     ring->supply = ring_increment(ring, ring->supply, count);
    182     ring->supplytime = ++ring_clock;
    183 }
    184 
    185 /*
    186  * We have just consumed "c" bytes.
    187  */
    188     void
    189 ring_consumed(ring, count)
    190     Ring *ring;
    191     int count;
    192 {
    193     if (count == 0)	/* don't update anything */
    194 	return;
    195 
    196     if (ring->mark &&
    197 		(ring_subtract(ring, ring->mark, ring->consume) < count)) {
    198 	ring->mark = 0;
    199     }
    200 #ifdef	ENCRYPTION
    201     if (ring->consume < ring->clearto &&
    202 		ring->clearto <= ring->consume + count)
    203 	ring->clearto = 0;
    204     else if (ring->consume + count > ring->top &&
    205 		ring->bottom <= ring->clearto &&
    206 		ring->bottom + ((ring->consume + count) - ring->top))
    207 	ring->clearto = 0;
    208 #endif	/* ENCRYPTION */
    209     ring->consume = ring_increment(ring, ring->consume, count);
    210     ring->consumetime = ++ring_clock;
    211     /*
    212      * Try to encourage "ring_empty_consecutive()" to be large.
    213      */
    214     if (ring_empty(ring)) {
    215 	ring->consume = ring->supply = ring->bottom;
    216     }
    217 }
    218 
    219 
    220 
    221 /* Buffer state query routines */
    222 
    223 
    224 /* Number of bytes that may be supplied */
    225     int
    226 ring_empty_count(ring)
    227     Ring *ring;
    228 {
    229     if (ring_empty(ring)) {	/* if empty */
    230 	    return ring->size;
    231     } else {
    232 	return ring_subtract(ring, ring->consume, ring->supply);
    233     }
    234 }
    235 
    236 /* number of CONSECUTIVE bytes that may be supplied */
    237     int
    238 ring_empty_consecutive(ring)
    239     Ring *ring;
    240 {
    241     if ((ring->consume < ring->supply) || ring_empty(ring)) {
    242 			    /*
    243 			     * if consume is "below" supply, or empty, then
    244 			     * return distance to the top
    245 			     */
    246 	return ring_subtract(ring, ring->top, ring->supply);
    247     } else {
    248 				    /*
    249 				     * else, return what we may.
    250 				     */
    251 	return ring_subtract(ring, ring->consume, ring->supply);
    252     }
    253 }
    254 
    255 /* Return the number of bytes that are available for consuming
    256  * (but don't give more than enough to get to cross over set mark)
    257  */
    258 
    259     int
    260 ring_full_count(ring)
    261     Ring *ring;
    262 {
    263     if ((ring->mark == 0) || (ring->mark == ring->consume)) {
    264 	if (ring_full(ring)) {
    265 	    return ring->size;	/* nothing consumed, but full */
    266 	} else {
    267 	    return ring_subtract(ring, ring->supply, ring->consume);
    268 	}
    269     } else {
    270 	return ring_subtract(ring, ring->mark, ring->consume);
    271     }
    272 }
    273 
    274 /*
    275  * Return the number of CONSECUTIVE bytes available for consuming.
    276  * However, don't return more than enough to cross over set mark.
    277  */
    278     int
    279 ring_full_consecutive(ring)
    280     Ring *ring;
    281 {
    282     if ((ring->mark == 0) || (ring->mark == ring->consume)) {
    283 	if ((ring->supply < ring->consume) || ring_full(ring)) {
    284 	    return ring_subtract(ring, ring->top, ring->consume);
    285 	} else {
    286 	    return ring_subtract(ring, ring->supply, ring->consume);
    287 	}
    288     } else {
    289 	if (ring->mark < ring->consume) {
    290 	    return ring_subtract(ring, ring->top, ring->consume);
    291 	} else {	/* Else, distance to mark */
    292 	    return ring_subtract(ring, ring->mark, ring->consume);
    293 	}
    294     }
    295 }
    296 
    297 /*
    298  * Move data into the "supply" portion of of the ring buffer.
    299  */
    300     void
    301 ring_supply_data(ring, buffer, count)
    302     Ring *ring;
    303     unsigned char *buffer;
    304     int count;
    305 {
    306     int i;
    307 
    308     while (count) {
    309 	i = MIN(count, ring_empty_consecutive(ring));
    310 	memmove(ring->supply, buffer, i);
    311 	ring_supplied(ring, i);
    312 	count -= i;
    313 	buffer += i;
    314     }
    315 }
    316 
    317 #ifdef notdef
    318 
    319 /*
    320  * Move data from the "consume" portion of the ring buffer
    321  */
    322     void
    323 ring_consume_data(ring, buffer, count)
    324     Ring *ring;
    325     unsigned char *buffer;
    326     int count;
    327 {
    328     int i;
    329 
    330     while (count) {
    331 	i = MIN(count, ring_full_consecutive(ring));
    332 	memmove(buffer, ring->consume, i);
    333 	ring_consumed(ring, i);
    334 	count -= i;
    335 	buffer += i;
    336     }
    337 }
    338 #endif
    339 
    340 #ifdef	ENCRYPTION
    341 void
    342 ring_encrypt(ring, encryptor)
    343 	Ring *ring;
    344 	void (*encryptor) P((unsigned char *, int));
    345 {
    346 	unsigned char *s, *c;
    347 
    348 	if (ring_empty(ring) || ring->clearto == ring->supply)
    349 		return;
    350 
    351 	if (!(c = ring->clearto))
    352 		c = ring->consume;
    353 
    354 	s = ring->supply;
    355 
    356 	if (s <= c) {
    357 		(*encryptor)(c, ring->top - c);
    358 		(*encryptor)(ring->bottom, s - ring->bottom);
    359 	} else
    360 		(*encryptor)(c, s - c);
    361 
    362 	ring->clearto = ring->supply;
    363 }
    364 
    365 void
    366 ring_clearto(ring)
    367 	Ring *ring;
    368 {
    369 
    370 	if (!ring_empty(ring))
    371 		ring->clearto = ring->supply;
    372 	else
    373 		ring->clearto = 0;
    374 }
    375 #endif	/* ENCRYPTION */
    376