buffer.c revision 126274
113044Sasami/*
2116111Sphk * Author: Tatu Ylonen <ylo@cs.hut.fi>
313044Sasami * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
413044Sasami *                    All rights reserved
513044Sasami * Functions for manipulating fifo buffers (that can grow if needed).
613044Sasami *
713044Sasami * As far as I am concerned, the code I have written for this software
813044Sasami * can be used freely for any purpose.  Any derived versions of this
913044Sasami * software must be clearly marked as such, and if the derived work is
1013044Sasami * incompatible with the protocol description in the RFC file, it must be
1113044Sasami * called by a name other than "ssh" or "Secure Shell".
1213044Sasami */
1313044Sasami
1413044Sasami#include "includes.h"
1513044SasamiRCSID("$OpenBSD: buffer.c,v 1.21 2003/11/21 11:57:03 djm Exp $");
1613044Sasami
1713044Sasami#include "xmalloc.h"
1813044Sasami#include "buffer.h"
1913044Sasami#include "log.h"
2013044Sasami
2113044Sasami/* Initializes the buffer structure. */
2213044Sasami
2313044Sasamivoid
2413044Sasamibuffer_init(Buffer *buffer)
2513044Sasami{
2613044Sasami	const u_int len = 4096;
2713044Sasami
2813044Sasami	buffer->alloc = 0;
2913044Sasami	buffer->buf = xmalloc(len);
3013044Sasami	buffer->alloc = len;
3113044Sasami	buffer->offset = 0;
3213044Sasami	buffer->end = 0;
3313044Sasami}
34114589Sobrien
35114589Sobrien/* Frees any memory used for the buffer. */
3636628Scharnier
3713044Sasamivoid
3848568Sbillfbuffer_free(Buffer *buffer)
3945329Speter{
4013044Sasami	if (buffer->alloc > 0) {
4113044Sasami		memset(buffer->buf, 0, buffer->alloc);
4213044Sasami		buffer->alloc = 0;
4313044Sasami		xfree(buffer->buf);
4469793Sobrien	}
4513044Sasami}
4613044Sasami
4713044Sasami/*
4813044Sasami * Clears any data from the buffer, making it empty.  This does not actually
49115730Sphk * zero the memory.
5013044Sasami */
51116111Sphk
52116111Sphkvoid
5313044Sasamibuffer_clear(Buffer *buffer)
5413044Sasami{
5513044Sasami	buffer->offset = 0;
5613044Sasami	buffer->end = 0;
5713044Sasami}
58109417Sphk
5913044Sasami/* Appends data to the buffer, expanding it if necessary. */
6013044Sasami
61109417Sphkvoid
62116111Sphkbuffer_append(Buffer *buffer, const void *data, u_int len)
6313044Sasami{
6413044Sasami	void *p;
65116111Sphk	p = buffer_append_space(buffer, len);
6613762Sasami	memcpy(p, data, len);
67116111Sphk}
68116111Sphk
6913044Sasami/*
7013044Sasami * Appends space to the buffer, expanding the buffer if necessary. This does
7113044Sasami * not actually copy the data into the buffer, but instead returns a pointer
7213044Sasami * to the allocated region.
7313044Sasami */
7413044Sasami
7513044Sasamivoid *
7613044Sasamibuffer_append_space(Buffer *buffer, u_int len)
7713044Sasami{
7892539Simp	u_int newlen;
7992539Simp	void *p;
8092539Simp
8192539Simp	if (len > 0x100000)
82109417Sphk		fatal("buffer_append_space: len %u not supported", len);
8392539Simp
8413044Sasami	/* If the buffer is empty, start using it from the beginning. */
8513044Sasami	if (buffer->offset == buffer->end) {
8692539Simp		buffer->offset = 0;
8713044Sasami		buffer->end = 0;
8813044Sasami	}
8913044Sasamirestart:
9083329Sru	/* If there is enough space to store all data, store it now. */
9113044Sasami	if (buffer->end + len < buffer->alloc) {
9213044Sasami		p = buffer->buf + buffer->end;
9313044Sasami		buffer->end += len;
9413044Sasami		return p;
9513044Sasami	}
9613044Sasami	/*
9713044Sasami	 * If the buffer is quite empty, but all data is at the end, move the
9813044Sasami	 * data to the beginning and retry.
9913044Sasami	 */
10013044Sasami	if (buffer->offset > buffer->alloc / 2) {
10113044Sasami		memmove(buffer->buf, buffer->buf + buffer->offset,
10213044Sasami			buffer->end - buffer->offset);
10313044Sasami		buffer->end -= buffer->offset;
10413044Sasami		buffer->offset = 0;
10513044Sasami		goto restart;
10613044Sasami	}
10713044Sasami	/* Increase the size of the buffer and retry. */
10813044Sasami
10913044Sasami	newlen = buffer->alloc + len + 32768;
11013044Sasami	if (newlen > 0xa00000)
11113044Sasami		fatal("buffer_append_space: alloc %u not supported",
11213044Sasami		    newlen);
11313044Sasami	buffer->buf = xrealloc(buffer->buf, newlen);
11413044Sasami	buffer->alloc = newlen;
11513044Sasami	goto restart;
11613044Sasami	/* NOTREACHED */
11713044Sasami}
11813044Sasami
11913044Sasami/* Returns the number of bytes of data in the buffer. */
12013044Sasami
12113044Sasamiu_int
12213044Sasamibuffer_len(Buffer *buffer)
12313044Sasami{
12413044Sasami	return buffer->end - buffer->offset;
12513044Sasami}
12613044Sasami
12713044Sasami/* Gets data from the beginning of the buffer. */
12813044Sasami
12913044Sasamivoid
13013044Sasamibuffer_get(Buffer *buffer, void *buf, u_int len)
13113044Sasami{
13213044Sasami	if (len > buffer->end - buffer->offset)
13313044Sasami		fatal("buffer_get: trying to get more bytes %d than in buffer %d",
134116111Sphk		    len, buffer->end - buffer->offset);
13545329Speter	memcpy(buf, buffer->buf + buffer->offset, len);
136116126Sphk	buffer->offset += len;
137116126Sphk}
13845329Speter
13945329Speter/* Consumes the given number of bytes from the beginning of the buffer. */
14013044Sasami
14113044Sasamivoid
14213044Sasamibuffer_consume(Buffer *buffer, u_int bytes)
14313044Sasami{
14413044Sasami	if (bytes > buffer->end - buffer->offset)
14513044Sasami		fatal("buffer_consume: trying to get more bytes than in buffer");
14613044Sasami	buffer->offset += bytes;
14713044Sasami}
14813044Sasami
14913044Sasami/* Consumes the given number of bytes from the end of the buffer. */
15013044Sasami
15113044Sasamivoid
15213044Sasamibuffer_consume_end(Buffer *buffer, u_int bytes)
15313044Sasami{
15413044Sasami	if (bytes > buffer->end - buffer->offset)
15513044Sasami		fatal("buffer_consume_end: trying to get more bytes than in buffer");
15636628Scharnier	buffer->end -= bytes;
15713044Sasami}
15813044Sasami
15913044Sasami/* Returns a pointer to the first used byte in the buffer. */
16092539Simp
16113044Sasamivoid *
162116111Sphkbuffer_ptr(Buffer *buffer)
163116111Sphk{
164116111Sphk	return buffer->buf + buffer->offset;
165116111Sphk}
166116111Sphk
167116111Sphk/* Dumps the contents of the buffer to stderr. */
16813044Sasami
16913044Sasamivoid
17013044Sasamibuffer_dump(Buffer *buffer)
17113044Sasami{
17213044Sasami	u_int i;
173116111Sphk	u_char *ucp = buffer->buf;
17413044Sasami
17513044Sasami	for (i = buffer->offset; i < buffer->end; i++) {
176109472Sphk		fprintf(stderr, "%02x", ucp[i]);
17713044Sasami		if ((i-buffer->offset)%16==15)
17813044Sasami			fprintf(stderr, "\r\n");
17913044Sasami		else if ((i-buffer->offset)%2==1)
18013044Sasami			fprintf(stderr, " ");
181116111Sphk	}
182116111Sphk	fprintf(stderr, "\r\n");
183116111Sphk}
184116111Sphk