1 /* $OpenBSD: buffer.c,v 1.27 2006/04/16 00:48:52 djm Exp $ */
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 * Functions for manipulating fifo buffers (that can grow if needed).
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".
21 #define BUFFER_MAX_CHUNK 0x100000
22 #define BUFFER_MAX_LEN 0xa00000
23 #define BUFFER_ALLOCSZ 0x008000
25 /* Initializes the buffer structure. */
28 buffer_init(Buffer
*buffer
)
30 const u_int len
= 4096;
33 buffer
->buf
= xmalloc(len
);
39 /* Frees any memory used for the buffer. */
42 buffer_free(Buffer
*buffer
)
44 if (buffer
->alloc
> 0) {
45 memset(buffer
->buf
, 0, buffer
->alloc
);
52 * Clears any data from the buffer, making it empty. This does not actually
57 buffer_clear(Buffer
*buffer
)
63 /* Appends data to the buffer, expanding it if necessary. */
66 buffer_append(Buffer
*buffer
, const void *data
, u_int len
)
69 p
= buffer_append_space(buffer
, len
);
74 buffer_compact(Buffer
*buffer
)
77 * If the buffer is quite empty, but all data is at the end, move the
78 * data to the beginning.
80 if (buffer
->offset
> MIN(buffer
->alloc
, BUFFER_MAX_CHUNK
)) {
81 memmove(buffer
->buf
, buffer
->buf
+ buffer
->offset
,
82 buffer
->end
- buffer
->offset
);
83 buffer
->end
-= buffer
->offset
;
91 * Appends space to the buffer, expanding the buffer if necessary. This does
92 * not actually copy the data into the buffer, but instead returns a pointer
93 * to the allocated region.
97 buffer_append_space(Buffer
*buffer
, u_int len
)
102 if (len
> BUFFER_MAX_CHUNK
)
103 fatal("buffer_append_space: len %u not supported", len
);
105 /* If the buffer is empty, start using it from the beginning. */
106 if (buffer
->offset
== buffer
->end
) {
111 /* If there is enough space to store all data, store it now. */
112 if (buffer
->end
+ len
< buffer
->alloc
) {
113 p
= buffer
->buf
+ buffer
->end
;
118 /* Compact data back to the start of the buffer if necessary */
119 if (buffer_compact(buffer
))
122 /* Increase the size of the buffer and retry. */
123 newlen
= roundup(buffer
->alloc
+ len
, BUFFER_ALLOCSZ
);
124 if (newlen
> BUFFER_MAX_LEN
)
125 fatal("buffer_append_space: alloc %u not supported",
127 buffer
->buf
= xrealloc(buffer
->buf
, 1, newlen
);
128 buffer
->alloc
= newlen
;
134 * Check whether an allocation of 'len' will fit in the buffer
135 * This must follow the same math as buffer_append_space
138 buffer_check_alloc(Buffer
*buffer
, u_int len
)
140 if (buffer
->offset
== buffer
->end
) {
145 if (buffer
->end
+ len
< buffer
->alloc
)
147 if (buffer_compact(buffer
))
149 if (roundup(buffer
->alloc
+ len
, BUFFER_ALLOCSZ
) <= BUFFER_MAX_LEN
)
154 /* Returns the number of bytes of data in the buffer. */
157 buffer_len(Buffer
*buffer
)
159 return buffer
->end
- buffer
->offset
;
162 /* Gets data from the beginning of the buffer. */
165 buffer_get_ret(Buffer
*buffer
, void *buf
, u_int len
)
167 if (len
> buffer
->end
- buffer
->offset
) {
168 error("buffer_get_ret: trying to get more bytes %d than in buffer %d",
169 len
, buffer
->end
- buffer
->offset
);
172 memcpy(buf
, buffer
->buf
+ buffer
->offset
, len
);
173 buffer
->offset
+= len
;
178 buffer_get(Buffer
*buffer
, void *buf
, u_int len
)
180 if (buffer_get_ret(buffer
, buf
, len
) == -1)
181 fatal("buffer_get: buffer error");
184 /* Consumes the given number of bytes from the beginning of the buffer. */
187 buffer_consume_ret(Buffer
*buffer
, u_int bytes
)
189 if (bytes
> buffer
->end
- buffer
->offset
) {
190 error("buffer_consume_ret: trying to get more bytes than in buffer");
193 buffer
->offset
+= bytes
;
198 buffer_consume(Buffer
*buffer
, u_int bytes
)
200 if (buffer_consume_ret(buffer
, bytes
) == -1)
201 fatal("buffer_consume: buffer error");
204 /* Consumes the given number of bytes from the end of the buffer. */
207 buffer_consume_end_ret(Buffer
*buffer
, u_int bytes
)
209 if (bytes
> buffer
->end
- buffer
->offset
)
211 buffer
->end
-= bytes
;
216 buffer_consume_end(Buffer
*buffer
, u_int bytes
)
218 if (buffer_consume_end_ret(buffer
, bytes
) == -1)
219 fatal("buffer_consume_end: trying to get more bytes than in buffer");
222 /* Returns a pointer to the first used byte in the buffer. */
225 buffer_ptr(Buffer
*buffer
)
227 return buffer
->buf
+ buffer
->offset
;
230 /* Dumps the contents of the buffer to stderr. */
233 buffer_dump(Buffer
*buffer
)
236 u_char
*ucp
= buffer
->buf
;
238 for (i
= buffer
->offset
; i
< buffer
->end
; i
++) {
239 fprintf(stderr
, "%02x", ucp
[i
]);
240 if ((i
-buffer
->offset
)%16==15)
241 fprintf(stderr
, "\r\n");
242 else if ((i
-buffer
->offset
)%2==1)
243 fprintf(stderr
, " ");
245 fprintf(stderr
, "\r\n");