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