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