2 /* $OpenBSD: buffer.c,v 1.31 2006/08/03 03:34:41 deraadt Exp $ */
4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
7 * Functions for manipulating fifo buffers (that can grow if needed).
9 * As far as I am concerned, the code I have written for this software
10 * can be used freely for any purpose. Any derived versions of this
11 * software must be clearly marked as such, and if the derived work is
12 * incompatible with the protocol description in the RFC file, it must be
13 * called by a name other than "ssh" or "Secure Shell".
17 __RCSID("$NetBSD: buffer.c,v 1.11 2009/02/16 20:53:54 christos Exp $");
18 #include <sys/param.h>
28 #define BUFFER_MAX_CHUNK 0x100000
29 #define BUFFER_MAX_LEN 0xa00000
30 #define BUFFER_ALLOCSZ 0x008000
32 /* Initializes the buffer structure. */
35 buffer_init(Buffer
*buffer
)
37 const u_int len
= 4096;
40 buffer
->buf
= xmalloc(len
);
46 /* Frees any memory used for the buffer. */
49 buffer_free(Buffer
*buffer
)
51 if (buffer
->alloc
> 0) {
52 memset(buffer
->buf
, 0, buffer
->alloc
);
59 * Clears any data from the buffer, making it empty. This does not actually
64 buffer_clear(Buffer
*buffer
)
70 /* Appends data to the buffer, expanding it if necessary. */
73 buffer_append(Buffer
*buffer
, const void *data
, u_int len
)
76 p
= buffer_append_space(buffer
, len
);
81 buffer_compact(Buffer
*buffer
)
84 * If the buffer is quite empty, but all data is at the end, move the
85 * data to the beginning.
87 if (buffer
->offset
> MIN(buffer
->alloc
, BUFFER_MAX_CHUNK
)) {
88 memmove(buffer
->buf
, buffer
->buf
+ buffer
->offset
,
89 buffer
->end
- buffer
->offset
);
90 buffer
->end
-= buffer
->offset
;
98 * Appends space to the buffer, expanding the buffer if necessary. This does
99 * not actually copy the data into the buffer, but instead returns a pointer
100 * to the allocated region.
104 buffer_append_space(Buffer
*buffer
, u_int len
)
109 if (len
> BUFFER_MAX_CHUNK
)
110 fatal("buffer_append_space: len %u not supported", len
);
112 /* If the buffer is empty, start using it from the beginning. */
113 if (buffer
->offset
== buffer
->end
) {
118 /* If there is enough space to store all data, store it now. */
119 if (buffer
->end
+ len
< buffer
->alloc
) {
120 p
= buffer
->buf
+ buffer
->end
;
125 /* Compact data back to the start of the buffer if necessary */
126 if (buffer_compact(buffer
))
129 /* Increase the size of the buffer and retry. */
130 newlen
= roundup(buffer
->alloc
+ len
, BUFFER_ALLOCSZ
);
131 if (newlen
> BUFFER_MAX_LEN_HPN
)
132 fatal("buffer_append_space: alloc %u not supported",
134 buffer
->buf
= xrealloc(buffer
->buf
, 1, newlen
);
135 buffer
->alloc
= newlen
;
141 * Check whether an allocation of 'len' will fit in the buffer
142 * This must follow the same math as buffer_append_space
145 buffer_check_alloc(Buffer
*buffer
, u_int len
)
147 if (buffer
->offset
== buffer
->end
) {
152 if (buffer
->end
+ len
< buffer
->alloc
)
154 if (buffer_compact(buffer
))
156 if (roundup(buffer
->alloc
+ len
, BUFFER_ALLOCSZ
) <= BUFFER_MAX_LEN
)
161 /* Returns the number of bytes of data in the buffer. */
164 buffer_len(Buffer
*buffer
)
166 return buffer
->end
- buffer
->offset
;
169 /* Gets data from the beginning of the buffer. */
172 buffer_get_ret(Buffer
*buffer
, void *buf
, u_int len
)
174 if (len
> buffer
->end
- buffer
->offset
) {
175 error("buffer_get_ret: trying to get more bytes %d than in buffer %d",
176 len
, buffer
->end
- buffer
->offset
);
179 memcpy(buf
, buffer
->buf
+ buffer
->offset
, len
);
180 buffer
->offset
+= len
;
185 buffer_get(Buffer
*buffer
, void *buf
, u_int len
)
187 if (buffer_get_ret(buffer
, buf
, len
) == -1)
188 fatal("buffer_get: buffer error");
191 /* Consumes the given number of bytes from the beginning of the buffer. */
194 buffer_consume_ret(Buffer
*buffer
, u_int bytes
)
196 if (bytes
> buffer
->end
- buffer
->offset
) {
197 error("buffer_consume_ret: trying to get more bytes than in buffer");
200 buffer
->offset
+= bytes
;
205 buffer_consume(Buffer
*buffer
, u_int bytes
)
207 if (buffer_consume_ret(buffer
, bytes
) == -1)
208 fatal("buffer_consume: buffer error");
211 /* Consumes the given number of bytes from the end of the buffer. */
214 buffer_consume_end_ret(Buffer
*buffer
, u_int bytes
)
216 if (bytes
> buffer
->end
- buffer
->offset
)
218 buffer
->end
-= bytes
;
223 buffer_consume_end(Buffer
*buffer
, u_int bytes
)
225 if (buffer_consume_end_ret(buffer
, bytes
) == -1)
226 fatal("buffer_consume_end: trying to get more bytes than in buffer");
229 /* Returns a pointer to the first used byte in the buffer. */
232 buffer_ptr(Buffer
*buffer
)
234 return buffer
->buf
+ buffer
->offset
;
237 /* Dumps the contents of the buffer to stderr. */
240 buffer_dump(Buffer
*buffer
)
243 u_char
*ucp
= buffer
->buf
;
245 for (i
= buffer
->offset
; i
< buffer
->end
; i
++) {
246 fprintf(stderr
, "%02x", ucp
[i
]);
247 if ((i
-buffer
->offset
)%16==15)
248 fprintf(stderr
, "\r\n");
249 else if ((i
-buffer
->offset
)%2==1)
250 fprintf(stderr
, " ");
252 fprintf(stderr
, "\r\n");