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