1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3*0Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4*0Sstevel@tonic-gate  *                    All rights reserved
5*0Sstevel@tonic-gate  * Functions for manipulating fifo buffers (that can grow if needed).
6*0Sstevel@tonic-gate  *
7*0Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
8*0Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
9*0Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
10*0Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
11*0Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
12*0Sstevel@tonic-gate  */
13*0Sstevel@tonic-gate 
14*0Sstevel@tonic-gate #include "includes.h"
15*0Sstevel@tonic-gate RCSID("$OpenBSD: buffer.c,v 1.16 2002/06/26 08:54:18 markus Exp $");
16*0Sstevel@tonic-gate 
17*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
18*0Sstevel@tonic-gate 
19*0Sstevel@tonic-gate #include "xmalloc.h"
20*0Sstevel@tonic-gate #include "buffer.h"
21*0Sstevel@tonic-gate #include "log.h"
22*0Sstevel@tonic-gate 
23*0Sstevel@tonic-gate /* Initializes the buffer structure. */
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate void
26*0Sstevel@tonic-gate buffer_init(Buffer *buffer)
27*0Sstevel@tonic-gate {
28*0Sstevel@tonic-gate 	const u_int len = 4096;
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate 	buffer->alloc = 0;
31*0Sstevel@tonic-gate 	buffer->buf = xmalloc(len);
32*0Sstevel@tonic-gate 	buffer->alloc = len;
33*0Sstevel@tonic-gate 	buffer->offset = 0;
34*0Sstevel@tonic-gate 	buffer->end = 0;
35*0Sstevel@tonic-gate }
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /* Frees any memory used for the buffer. */
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate void
40*0Sstevel@tonic-gate buffer_free(Buffer *buffer)
41*0Sstevel@tonic-gate {
42*0Sstevel@tonic-gate 	if (buffer->alloc > 0) {
43*0Sstevel@tonic-gate 		memset(buffer->buf, 0, buffer->alloc);
44*0Sstevel@tonic-gate 		xfree(buffer->buf);
45*0Sstevel@tonic-gate 	}
46*0Sstevel@tonic-gate }
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate /*
49*0Sstevel@tonic-gate  * Clears any data from the buffer, making it empty.  This does not actually
50*0Sstevel@tonic-gate  * zero the memory.
51*0Sstevel@tonic-gate  */
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate void
54*0Sstevel@tonic-gate buffer_clear(Buffer *buffer)
55*0Sstevel@tonic-gate {
56*0Sstevel@tonic-gate 	buffer->offset = 0;
57*0Sstevel@tonic-gate 	buffer->end = 0;
58*0Sstevel@tonic-gate }
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /* Appends data to the buffer, expanding it if necessary. */
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate void
63*0Sstevel@tonic-gate buffer_append(Buffer *buffer, const void *data, u_int len)
64*0Sstevel@tonic-gate {
65*0Sstevel@tonic-gate 	void *p;
66*0Sstevel@tonic-gate 	p = buffer_append_space(buffer, len);
67*0Sstevel@tonic-gate 	memcpy(p, data, len);
68*0Sstevel@tonic-gate }
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate /*
71*0Sstevel@tonic-gate  * Appends space to the buffer, expanding the buffer if necessary. This does
72*0Sstevel@tonic-gate  * not actually copy the data into the buffer, but instead returns a pointer
73*0Sstevel@tonic-gate  * to the allocated region.
74*0Sstevel@tonic-gate  */
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate void *
77*0Sstevel@tonic-gate buffer_append_space(Buffer *buffer, u_int len)
78*0Sstevel@tonic-gate {
79*0Sstevel@tonic-gate 	u_int newlen;
80*0Sstevel@tonic-gate 	void *p;
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	if (len > 0x100000)
83*0Sstevel@tonic-gate 		fatal("buffer_append_space: len %u not supported", len);
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	/* If the buffer is empty, start using it from the beginning. */
86*0Sstevel@tonic-gate 	if (buffer->offset == buffer->end) {
87*0Sstevel@tonic-gate 		buffer->offset = 0;
88*0Sstevel@tonic-gate 		buffer->end = 0;
89*0Sstevel@tonic-gate 	}
90*0Sstevel@tonic-gate restart:
91*0Sstevel@tonic-gate 	/* If there is enough space to store all data, store it now. */
92*0Sstevel@tonic-gate 	if (buffer->end + len < buffer->alloc) {
93*0Sstevel@tonic-gate 		p = buffer->buf + buffer->end;
94*0Sstevel@tonic-gate 		buffer->end += len;
95*0Sstevel@tonic-gate 		return p;
96*0Sstevel@tonic-gate 	}
97*0Sstevel@tonic-gate 	/*
98*0Sstevel@tonic-gate 	 * If the buffer is quite empty, but all data is at the end, move the
99*0Sstevel@tonic-gate 	 * data to the beginning and retry.
100*0Sstevel@tonic-gate 	 */
101*0Sstevel@tonic-gate 	if (buffer->offset > buffer->alloc / 2) {
102*0Sstevel@tonic-gate 		memmove(buffer->buf, buffer->buf + buffer->offset,
103*0Sstevel@tonic-gate 			buffer->end - buffer->offset);
104*0Sstevel@tonic-gate 		buffer->end -= buffer->offset;
105*0Sstevel@tonic-gate 		buffer->offset = 0;
106*0Sstevel@tonic-gate 		goto restart;
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate 	/* Increase the size of the buffer and retry. */
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	newlen = buffer->alloc + len + 32768;
111*0Sstevel@tonic-gate 	if (newlen > 0xa00000)
112*0Sstevel@tonic-gate 		fatal("buffer_append_space: alloc %u not supported",
113*0Sstevel@tonic-gate 		    newlen);
114*0Sstevel@tonic-gate 	buffer->buf = xrealloc(buffer->buf, newlen);
115*0Sstevel@tonic-gate 	buffer->alloc = newlen;
116*0Sstevel@tonic-gate 	goto restart;
117*0Sstevel@tonic-gate 	/* NOTREACHED */
118*0Sstevel@tonic-gate }
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate /* Returns the number of bytes of data in the buffer. */
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate u_int
123*0Sstevel@tonic-gate buffer_len(Buffer *buffer)
124*0Sstevel@tonic-gate {
125*0Sstevel@tonic-gate 	return buffer->end - buffer->offset;
126*0Sstevel@tonic-gate }
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate /* Gets data from the beginning of the buffer. */
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate void
131*0Sstevel@tonic-gate buffer_get(Buffer *buffer, void *buf, u_int len)
132*0Sstevel@tonic-gate {
133*0Sstevel@tonic-gate 	if (len > buffer->end - buffer->offset)
134*0Sstevel@tonic-gate 		fatal("buffer_get: trying to get more bytes %d than in buffer %d",
135*0Sstevel@tonic-gate 		    len, buffer->end - buffer->offset);
136*0Sstevel@tonic-gate 	memcpy(buf, buffer->buf + buffer->offset, len);
137*0Sstevel@tonic-gate 	buffer->offset += len;
138*0Sstevel@tonic-gate }
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate /* Consumes the given number of bytes from the beginning of the buffer. */
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate void
143*0Sstevel@tonic-gate buffer_consume(Buffer *buffer, u_int bytes)
144*0Sstevel@tonic-gate {
145*0Sstevel@tonic-gate 	if (bytes > buffer->end - buffer->offset)
146*0Sstevel@tonic-gate 		fatal("buffer_consume: trying to get more bytes than in buffer");
147*0Sstevel@tonic-gate 	buffer->offset += bytes;
148*0Sstevel@tonic-gate }
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate /* Consumes the given number of bytes from the end of the buffer. */
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate void
153*0Sstevel@tonic-gate buffer_consume_end(Buffer *buffer, u_int bytes)
154*0Sstevel@tonic-gate {
155*0Sstevel@tonic-gate 	if (bytes > buffer->end - buffer->offset)
156*0Sstevel@tonic-gate 		fatal("buffer_consume_end: trying to get more bytes than in buffer");
157*0Sstevel@tonic-gate 	buffer->end -= bytes;
158*0Sstevel@tonic-gate }
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate /* Returns a pointer to the first used byte in the buffer. */
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate void *
163*0Sstevel@tonic-gate buffer_ptr(Buffer *buffer)
164*0Sstevel@tonic-gate {
165*0Sstevel@tonic-gate 	return buffer->buf + buffer->offset;
166*0Sstevel@tonic-gate }
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate /* Dumps the contents of the buffer to stderr. */
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate void
171*0Sstevel@tonic-gate buffer_dump(Buffer *buffer)
172*0Sstevel@tonic-gate {
173*0Sstevel@tonic-gate 	int i;
174*0Sstevel@tonic-gate 	u_char *ucp = buffer->buf;
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	for (i = buffer->offset; i < buffer->end; i++) {
177*0Sstevel@tonic-gate 		fprintf(stderr, "%02x", ucp[i]);
178*0Sstevel@tonic-gate 		if ((i-buffer->offset)%16==15)
179*0Sstevel@tonic-gate 			fprintf(stderr, "\r\n");
180*0Sstevel@tonic-gate 		else if ((i-buffer->offset)%2==1)
181*0Sstevel@tonic-gate 			fprintf(stderr, " ");
182*0Sstevel@tonic-gate 	}
183*0Sstevel@tonic-gate 	fprintf(stderr, "\r\n");
184*0Sstevel@tonic-gate }
185