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