129088Smarkm/*
229088Smarkm * Copyright (c) 1988, 1993
329088Smarkm *	The Regents of the University of California.  All rights reserved.
429088Smarkm *
529088Smarkm * Redistribution and use in source and binary forms, with or without
629088Smarkm * modification, are permitted provided that the following conditions
729088Smarkm * are met:
829088Smarkm * 1. Redistributions of source code must retain the above copyright
929088Smarkm *    notice, this list of conditions and the following disclaimer.
1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1129088Smarkm *    notice, this list of conditions and the following disclaimer in the
1229088Smarkm *    documentation and/or other materials provided with the distribution.
13351432Semaste * 3. Neither the name of the University nor the names of its contributors
1429088Smarkm *    may be used to endorse or promote products derived from this software
1529088Smarkm *    without specific prior written permission.
1629088Smarkm *
1729088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1829088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1929088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2029088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2129088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2229088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2329088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2429088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2529088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2629088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2729088Smarkm * SUCH DAMAGE.
2829088Smarkm */
2929088Smarkm
30114630Sobrien#if 0
3129088Smarkm#ifndef lint
3229181Smarkmstatic const char sccsid[] = "@(#)ring.c	8.2 (Berkeley) 5/30/95";
3363248Speter#endif
34114630Sobrien#endif
35114630Sobrien#include <sys/cdefs.h>
36114630Sobrien__FBSDID("$FreeBSD: stable/11/contrib/telnet/telnet/ring.c 351432 2019-08-23 17:40:47Z emaste $");
3729088Smarkm
3829088Smarkm/*
3929088Smarkm * This defines a structure for a ring buffer.
4029088Smarkm *
4129088Smarkm * The circular buffer has two parts:
4229088Smarkm *(((
4329088Smarkm *	full:	[consume, supply)
4429088Smarkm *	empty:	[supply, consume)
4529088Smarkm *]]]
4629088Smarkm *
4729088Smarkm */
4829088Smarkm
4981965Smarkm#include	<errno.h>
5029088Smarkm#include	<stdio.h>
5129181Smarkm#include	<string.h>
5229088Smarkm
5329088Smarkm#ifdef	size_t
5429088Smarkm#undef	size_t
5529088Smarkm#endif
5629088Smarkm
5729088Smarkm#include	<sys/types.h>
5829088Smarkm#ifndef	FILIO_H
5929088Smarkm#include	<sys/ioctl.h>
6029088Smarkm#endif
6129088Smarkm#include	<sys/socket.h>
6229088Smarkm
6329088Smarkm#include	"ring.h"
6429088Smarkm#include	"general.h"
6529088Smarkm
6629088Smarkm/* Internal macros */
6729088Smarkm
6829088Smarkm#if	!defined(MIN)
6929088Smarkm#define	MIN(a,b)	(((a)<(b))? (a):(b))
7029088Smarkm#endif	/* !defined(MIN) */
7129088Smarkm
7229088Smarkm#define	ring_subtract(d,a,b)	(((a)-(b) >= 0)? \
7329088Smarkm					(a)-(b): (((a)-(b))+(d)->size))
7429088Smarkm
7529088Smarkm#define	ring_increment(d,a,c)	(((a)+(c) < (d)->top)? \
7629088Smarkm					(a)+(c) : (((a)+(c))-(d)->size))
7729088Smarkm
7829088Smarkm#define	ring_decrement(d,a,c)	(((a)-(c) >= (d)->bottom)? \
7929088Smarkm					(a)-(c) : (((a)-(c))-(d)->size))
8029088Smarkm
8129088Smarkm
8229088Smarkm/*
8329088Smarkm * The following is a clock, used to determine full, empty, etc.
8429088Smarkm *
8529088Smarkm * There is some trickiness here.  Since the ring buffers are initialized
8629088Smarkm * to ZERO on allocation, we need to make sure, when interpreting the
8729088Smarkm * clock, that when the times are EQUAL, then the buffer is FULL.
8829088Smarkm */
8929088Smarkmstatic u_long ring_clock = 0;
9029088Smarkm
9129088Smarkm
9229088Smarkm#define	ring_empty(d) (((d)->consume == (d)->supply) && \
9329088Smarkm				((d)->consumetime >= (d)->supplytime))
9429088Smarkm#define	ring_full(d) (((d)->supply == (d)->consume) && \
9529088Smarkm				((d)->supplytime > (d)->consumetime))
9629088Smarkm
9729088Smarkm/* Buffer state transition routines */
9829088Smarkm
9987139Smarkmint
10087139Smarkmring_init(Ring *ring, unsigned char *buffer, int count)
10129088Smarkm{
10229088Smarkm    memset((char *)ring, 0, sizeof *ring);
10329088Smarkm
10429088Smarkm    ring->size = count;
10529088Smarkm
10629088Smarkm    ring->supply = ring->consume = ring->bottom = buffer;
10729088Smarkm
10829088Smarkm    ring->top = ring->bottom+ring->size;
10929088Smarkm
11029088Smarkm#ifdef	ENCRYPTION
11129088Smarkm    ring->clearto = 0;
11229088Smarkm#endif	/* ENCRYPTION */
11329088Smarkm
11429088Smarkm    return 1;
11529088Smarkm}
11629088Smarkm
11729088Smarkm/* Mark routines */
11829088Smarkm
11929088Smarkm/*
12029088Smarkm * Mark the most recently supplied byte.
12129088Smarkm */
12229088Smarkm
12387139Smarkmvoid
12487139Smarkmring_mark(Ring *ring)
12529088Smarkm{
12629088Smarkm    ring->mark = ring_decrement(ring, ring->supply, 1);
12729088Smarkm}
12829088Smarkm
12929088Smarkm/*
13029088Smarkm * Is the ring pointing to the mark?
13129088Smarkm */
13229088Smarkm
13387139Smarkmint
13487139Smarkmring_at_mark(Ring *ring)
13529088Smarkm{
13629088Smarkm    if (ring->mark == ring->consume) {
13729088Smarkm	return 1;
13829088Smarkm    } else {
13929088Smarkm	return 0;
14029088Smarkm    }
14129088Smarkm}
14229088Smarkm
14329088Smarkm/*
14429088Smarkm * Clear any mark set on the ring.
14529088Smarkm */
14629088Smarkm
14787139Smarkmvoid
14887139Smarkmring_clear_mark(Ring *ring)
14929088Smarkm{
15029088Smarkm    ring->mark = 0;
15129088Smarkm}
15229088Smarkm
15329088Smarkm/*
15429088Smarkm * Add characters from current segment to ring buffer.
15529088Smarkm */
15687139Smarkmvoid
15787139Smarkmring_supplied(Ring *ring, int count)
15829088Smarkm{
15929088Smarkm    ring->supply = ring_increment(ring, ring->supply, count);
16029088Smarkm    ring->supplytime = ++ring_clock;
16129088Smarkm}
16229088Smarkm
16329088Smarkm/*
16429088Smarkm * We have just consumed "c" bytes.
16529088Smarkm */
16687139Smarkmvoid
16787139Smarkmring_consumed(Ring *ring, int count)
16829088Smarkm{
16929088Smarkm    if (count == 0)	/* don't update anything */
17029088Smarkm	return;
17129088Smarkm
17229088Smarkm    if (ring->mark &&
17329088Smarkm		(ring_subtract(ring, ring->mark, ring->consume) < count)) {
17429088Smarkm	ring->mark = 0;
17529088Smarkm    }
17629088Smarkm#ifdef	ENCRYPTION
17729088Smarkm    if (ring->consume < ring->clearto &&
17829088Smarkm		ring->clearto <= ring->consume + count)
17929088Smarkm	ring->clearto = 0;
18029088Smarkm    else if (ring->consume + count > ring->top &&
18129088Smarkm		ring->bottom <= ring->clearto &&
18229088Smarkm		ring->bottom + ((ring->consume + count) - ring->top))
18329088Smarkm	ring->clearto = 0;
18429088Smarkm#endif	/* ENCRYPTION */
18529088Smarkm    ring->consume = ring_increment(ring, ring->consume, count);
18629088Smarkm    ring->consumetime = ++ring_clock;
18729088Smarkm    /*
18829088Smarkm     * Try to encourage "ring_empty_consecutive()" to be large.
18929088Smarkm     */
19029088Smarkm    if (ring_empty(ring)) {
19129088Smarkm	ring->consume = ring->supply = ring->bottom;
19229088Smarkm    }
19329088Smarkm}
19429088Smarkm
19529088Smarkm
19629088Smarkm
19729088Smarkm/* Buffer state query routines */
19829088Smarkm
19929088Smarkm
20029088Smarkm/* Number of bytes that may be supplied */
20187139Smarkmint
20287139Smarkmring_empty_count(Ring *ring)
20329088Smarkm{
20429088Smarkm    if (ring_empty(ring)) {	/* if empty */
20529088Smarkm	    return ring->size;
20629088Smarkm    } else {
20729088Smarkm	return ring_subtract(ring, ring->consume, ring->supply);
20829088Smarkm    }
20929088Smarkm}
21029088Smarkm
21129088Smarkm/* number of CONSECUTIVE bytes that may be supplied */
21287139Smarkmint
21387139Smarkmring_empty_consecutive(Ring *ring)
21429088Smarkm{
21529088Smarkm    if ((ring->consume < ring->supply) || ring_empty(ring)) {
21629088Smarkm			    /*
21729088Smarkm			     * if consume is "below" supply, or empty, then
21829088Smarkm			     * return distance to the top
21929088Smarkm			     */
22029088Smarkm	return ring_subtract(ring, ring->top, ring->supply);
22129088Smarkm    } else {
22229088Smarkm				    /*
22329088Smarkm				     * else, return what we may.
22429088Smarkm				     */
22529088Smarkm	return ring_subtract(ring, ring->consume, ring->supply);
22629088Smarkm    }
22729088Smarkm}
22829088Smarkm
22929088Smarkm/* Return the number of bytes that are available for consuming
23029088Smarkm * (but don't give more than enough to get to cross over set mark)
23129088Smarkm */
23229088Smarkm
23387139Smarkmint
23487139Smarkmring_full_count(Ring *ring)
23529088Smarkm{
23629088Smarkm    if ((ring->mark == 0) || (ring->mark == ring->consume)) {
23729088Smarkm	if (ring_full(ring)) {
23829088Smarkm	    return ring->size;	/* nothing consumed, but full */
23929088Smarkm	} else {
24029088Smarkm	    return ring_subtract(ring, ring->supply, ring->consume);
24129088Smarkm	}
24229088Smarkm    } else {
24329088Smarkm	return ring_subtract(ring, ring->mark, ring->consume);
24429088Smarkm    }
24529088Smarkm}
24629088Smarkm
24729088Smarkm/*
24829088Smarkm * Return the number of CONSECUTIVE bytes available for consuming.
24929088Smarkm * However, don't return more than enough to cross over set mark.
25029088Smarkm */
25187139Smarkmint
25287139Smarkmring_full_consecutive(Ring *ring)
25329088Smarkm{
25429088Smarkm    if ((ring->mark == 0) || (ring->mark == ring->consume)) {
25529088Smarkm	if ((ring->supply < ring->consume) || ring_full(ring)) {
25629088Smarkm	    return ring_subtract(ring, ring->top, ring->consume);
25729088Smarkm	} else {
25829088Smarkm	    return ring_subtract(ring, ring->supply, ring->consume);
25929088Smarkm	}
26029088Smarkm    } else {
26129088Smarkm	if (ring->mark < ring->consume) {
26229088Smarkm	    return ring_subtract(ring, ring->top, ring->consume);
26329088Smarkm	} else {	/* Else, distance to mark */
26429088Smarkm	    return ring_subtract(ring, ring->mark, ring->consume);
26529088Smarkm	}
26629088Smarkm    }
26729088Smarkm}
26829088Smarkm
26929088Smarkm/*
27029088Smarkm * Move data into the "supply" portion of of the ring buffer.
27129088Smarkm */
27287139Smarkmvoid
27387139Smarkmring_supply_data(Ring *ring, unsigned char *buffer, int count)
27429088Smarkm{
27529088Smarkm    int i;
27629088Smarkm
27729088Smarkm    while (count) {
27829088Smarkm	i = MIN(count, ring_empty_consecutive(ring));
27981965Smarkm	memcpy(ring->supply, buffer, i);
28029088Smarkm	ring_supplied(ring, i);
28129088Smarkm	count -= i;
28229088Smarkm	buffer += i;
28329088Smarkm    }
28429088Smarkm}
28529088Smarkm
28629088Smarkm#ifdef	ENCRYPTION
28787139Smarkmvoid
28887139Smarkmring_encrypt(Ring *ring, void (*encryptor)(unsigned char *, int))
28929088Smarkm{
29029088Smarkm    unsigned char *s, *c;
29129088Smarkm
29229088Smarkm    if (ring_empty(ring) || ring->clearto == ring->supply)
29329088Smarkm	return;
29429088Smarkm
29529088Smarkm    if (!(c = ring->clearto))
29629088Smarkm	c = ring->consume;
29729088Smarkm
29829088Smarkm    s = ring->supply;
29929088Smarkm
30029088Smarkm    if (s <= c) {
30129088Smarkm	(*encryptor)(c, ring->top - c);
30229088Smarkm	(*encryptor)(ring->bottom, s - ring->bottom);
30329088Smarkm    } else
30429088Smarkm	(*encryptor)(c, s - c);
30529088Smarkm
30629088Smarkm    ring->clearto = ring->supply;
30729088Smarkm}
30829088Smarkm
30929088Smarkm    void
31029088Smarkmring_clearto(ring)
31129088Smarkm    Ring *ring;
31229088Smarkm{
31329088Smarkm    if (!ring_empty(ring))
31429088Smarkm	ring->clearto = ring->supply;
31529088Smarkm    else
31629088Smarkm	ring->clearto = 0;
31729088Smarkm}
31829088Smarkm#endif	/* ENCRYPTION */
319