10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
30Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
40Sstevel@tonic-gate  *                    All rights reserved
50Sstevel@tonic-gate  * Functions for manipulating fifo buffers (that can grow if needed).
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
80Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
90Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
100Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
110Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
120Sstevel@tonic-gate  */
130Sstevel@tonic-gate 
140Sstevel@tonic-gate #include "includes.h"
15*2757Sjp161948 RCSID("$OpenBSD: buffer.c,v 1.23 2005/03/14 11:46:56 markus Exp $");
160Sstevel@tonic-gate 
170Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
180Sstevel@tonic-gate 
190Sstevel@tonic-gate #include "xmalloc.h"
200Sstevel@tonic-gate #include "buffer.h"
210Sstevel@tonic-gate #include "log.h"
220Sstevel@tonic-gate 
230Sstevel@tonic-gate /* Initializes the buffer structure. */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate void
260Sstevel@tonic-gate buffer_init(Buffer *buffer)
270Sstevel@tonic-gate {
280Sstevel@tonic-gate 	const u_int len = 4096;
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 	buffer->alloc = 0;
310Sstevel@tonic-gate 	buffer->buf = xmalloc(len);
320Sstevel@tonic-gate 	buffer->alloc = len;
330Sstevel@tonic-gate 	buffer->offset = 0;
340Sstevel@tonic-gate 	buffer->end = 0;
350Sstevel@tonic-gate }
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /* Frees any memory used for the buffer. */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate void
400Sstevel@tonic-gate buffer_free(Buffer *buffer)
410Sstevel@tonic-gate {
420Sstevel@tonic-gate 	if (buffer->alloc > 0) {
430Sstevel@tonic-gate 		memset(buffer->buf, 0, buffer->alloc);
44*2757Sjp161948 		buffer->alloc = 0;
450Sstevel@tonic-gate 		xfree(buffer->buf);
460Sstevel@tonic-gate 	}
470Sstevel@tonic-gate }
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Clears any data from the buffer, making it empty.  This does not actually
510Sstevel@tonic-gate  * zero the memory.
520Sstevel@tonic-gate  */
530Sstevel@tonic-gate 
540Sstevel@tonic-gate void
550Sstevel@tonic-gate buffer_clear(Buffer *buffer)
560Sstevel@tonic-gate {
570Sstevel@tonic-gate 	buffer->offset = 0;
580Sstevel@tonic-gate 	buffer->end = 0;
590Sstevel@tonic-gate }
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /* Appends data to the buffer, expanding it if necessary. */
620Sstevel@tonic-gate 
630Sstevel@tonic-gate void
640Sstevel@tonic-gate buffer_append(Buffer *buffer, const void *data, u_int len)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 	void *p;
670Sstevel@tonic-gate 	p = buffer_append_space(buffer, len);
680Sstevel@tonic-gate 	memcpy(p, data, len);
690Sstevel@tonic-gate }
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * Appends space to the buffer, expanding the buffer if necessary. This does
730Sstevel@tonic-gate  * not actually copy the data into the buffer, but instead returns a pointer
740Sstevel@tonic-gate  * to the allocated region.
750Sstevel@tonic-gate  */
760Sstevel@tonic-gate 
770Sstevel@tonic-gate void *
780Sstevel@tonic-gate buffer_append_space(Buffer *buffer, u_int len)
790Sstevel@tonic-gate {
800Sstevel@tonic-gate 	u_int newlen;
810Sstevel@tonic-gate 	void *p;
820Sstevel@tonic-gate 
83*2757Sjp161948 	if (len > BUFFER_MAX_CHUNK)
840Sstevel@tonic-gate 		fatal("buffer_append_space: len %u not supported", len);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	/* If the buffer is empty, start using it from the beginning. */
870Sstevel@tonic-gate 	if (buffer->offset == buffer->end) {
880Sstevel@tonic-gate 		buffer->offset = 0;
890Sstevel@tonic-gate 		buffer->end = 0;
900Sstevel@tonic-gate 	}
910Sstevel@tonic-gate restart:
920Sstevel@tonic-gate 	/* If there is enough space to store all data, store it now. */
930Sstevel@tonic-gate 	if (buffer->end + len < buffer->alloc) {
940Sstevel@tonic-gate 		p = buffer->buf + buffer->end;
950Sstevel@tonic-gate 		buffer->end += len;
960Sstevel@tonic-gate 		return p;
970Sstevel@tonic-gate 	}
980Sstevel@tonic-gate 	/*
990Sstevel@tonic-gate 	 * If the buffer is quite empty, but all data is at the end, move the
1000Sstevel@tonic-gate 	 * data to the beginning and retry.
1010Sstevel@tonic-gate 	 */
102*2757Sjp161948 	if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) {
1030Sstevel@tonic-gate 		memmove(buffer->buf, buffer->buf + buffer->offset,
1040Sstevel@tonic-gate 			buffer->end - buffer->offset);
1050Sstevel@tonic-gate 		buffer->end -= buffer->offset;
1060Sstevel@tonic-gate 		buffer->offset = 0;
1070Sstevel@tonic-gate 		goto restart;
1080Sstevel@tonic-gate 	}
1090Sstevel@tonic-gate 	/* Increase the size of the buffer and retry. */
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	newlen = buffer->alloc + len + 32768;
112*2757Sjp161948 	if (newlen > BUFFER_MAX_LEN)
1130Sstevel@tonic-gate 		fatal("buffer_append_space: alloc %u not supported",
1140Sstevel@tonic-gate 		    newlen);
1150Sstevel@tonic-gate 	buffer->buf = xrealloc(buffer->buf, newlen);
1160Sstevel@tonic-gate 	buffer->alloc = newlen;
1170Sstevel@tonic-gate 	goto restart;
1180Sstevel@tonic-gate 	/* NOTREACHED */
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /* Returns the number of bytes of data in the buffer. */
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate u_int
1240Sstevel@tonic-gate buffer_len(Buffer *buffer)
1250Sstevel@tonic-gate {
1260Sstevel@tonic-gate 	return buffer->end - buffer->offset;
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate /* Gets data from the beginning of the buffer. */
1300Sstevel@tonic-gate 
131*2757Sjp161948 int
132*2757Sjp161948 buffer_get_ret(Buffer *buffer, void *buf, u_int len)
133*2757Sjp161948 {
134*2757Sjp161948 	if (len > buffer->end - buffer->offset) {
135*2757Sjp161948 		error("buffer_get_ret: trying to get more bytes %d than in buffer %d",
136*2757Sjp161948 		    len, buffer->end - buffer->offset);
137*2757Sjp161948 		return (-1);
138*2757Sjp161948 	}
139*2757Sjp161948 	memcpy(buf, buffer->buf + buffer->offset, len);
140*2757Sjp161948 	buffer->offset += len;
141*2757Sjp161948 	return (0);
142*2757Sjp161948 }
143*2757Sjp161948 
1440Sstevel@tonic-gate void
1450Sstevel@tonic-gate buffer_get(Buffer *buffer, void *buf, u_int len)
1460Sstevel@tonic-gate {
147*2757Sjp161948 	if (buffer_get_ret(buffer, buf, len) == -1)
148*2757Sjp161948 		fatal("buffer_get: buffer error");
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate /* Consumes the given number of bytes from the beginning of the buffer. */
1520Sstevel@tonic-gate 
153*2757Sjp161948 int
154*2757Sjp161948 buffer_consume_ret(Buffer *buffer, u_int bytes)
155*2757Sjp161948 {
156*2757Sjp161948 	if (bytes > buffer->end - buffer->offset) {
157*2757Sjp161948 		error("buffer_consume_ret: trying to get more bytes than in buffer");
158*2757Sjp161948 		return (-1);
159*2757Sjp161948 	}
160*2757Sjp161948 	buffer->offset += bytes;
161*2757Sjp161948 	return (0);
162*2757Sjp161948 }
163*2757Sjp161948 
1640Sstevel@tonic-gate void
1650Sstevel@tonic-gate buffer_consume(Buffer *buffer, u_int bytes)
1660Sstevel@tonic-gate {
167*2757Sjp161948 	if (buffer_consume_ret(buffer, bytes) == -1)
168*2757Sjp161948 		fatal("buffer_consume: buffer error");
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /* Consumes the given number of bytes from the end of the buffer. */
1720Sstevel@tonic-gate 
173*2757Sjp161948 int
174*2757Sjp161948 buffer_consume_end_ret(Buffer *buffer, u_int bytes)
175*2757Sjp161948 {
176*2757Sjp161948 	if (bytes > buffer->end - buffer->offset)
177*2757Sjp161948 		return (-1);
178*2757Sjp161948 	buffer->end -= bytes;
179*2757Sjp161948 	return (0);
180*2757Sjp161948 }
181*2757Sjp161948 
1820Sstevel@tonic-gate void
1830Sstevel@tonic-gate buffer_consume_end(Buffer *buffer, u_int bytes)
1840Sstevel@tonic-gate {
185*2757Sjp161948 	if (buffer_consume_end_ret(buffer, bytes) == -1)
1860Sstevel@tonic-gate 		fatal("buffer_consume_end: trying to get more bytes than in buffer");
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /* Returns a pointer to the first used byte in the buffer. */
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate void *
1920Sstevel@tonic-gate buffer_ptr(Buffer *buffer)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	return buffer->buf + buffer->offset;
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /* Dumps the contents of the buffer to stderr. */
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate void
2000Sstevel@tonic-gate buffer_dump(Buffer *buffer)
2010Sstevel@tonic-gate {
202*2757Sjp161948 	u_int i;
2030Sstevel@tonic-gate 	u_char *ucp = buffer->buf;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	for (i = buffer->offset; i < buffer->end; i++) {
2060Sstevel@tonic-gate 		fprintf(stderr, "%02x", ucp[i]);
2070Sstevel@tonic-gate 		if ((i-buffer->offset)%16==15)
2080Sstevel@tonic-gate 			fprintf(stderr, "\r\n");
2090Sstevel@tonic-gate 		else if ((i-buffer->offset)%2==1)
2100Sstevel@tonic-gate 			fprintf(stderr, " ");
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 	fprintf(stderr, "\r\n");
2130Sstevel@tonic-gate }
214