1 /* $OpenBSD: buffer.c,v 1.32 2010/02/09 03:56:28 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".
17 #include <sys/param.h>
27 #define BUFFER_MAX_CHUNK 0x100000
28 #define BUFFER_MAX_LEN 0xa00000
29 #define BUFFER_ALLOCSZ 0x008000
31 /* Initializes the buffer structure. */
34 buffer_init(Buffer
*buffer
)
36 const u_int len
= 4096;
39 buffer
->buf
= xmalloc(len
);
45 /* Frees any memory used for the buffer. */
48 buffer_free(Buffer
*buffer
)
50 if (buffer
->alloc
> 0) {
51 memset(buffer
->buf
, 0, buffer
->alloc
);
58 * Clears any data from the buffer, making it empty. This does not actually
63 buffer_clear(Buffer
*buffer
)
69 /* Appends data to the buffer, expanding it if necessary. */
72 buffer_append(Buffer
*buffer
, const void *data
, u_int len
)
75 p
= buffer_append_space(buffer
, len
);
80 buffer_compact(Buffer
*buffer
)
83 * If the buffer is quite empty, but all data is at the end, move the
84 * data to the beginning.
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
;
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.
103 buffer_append_space(Buffer
*buffer
, u_int len
)
108 if (len
> BUFFER_MAX_CHUNK
)
109 fatal("buffer_append_space: len %u not supported", len
);
111 /* If the buffer is empty, start using it from the beginning. */
112 if (buffer
->offset
== buffer
->end
) {
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
;
124 /* Compact data back to the start of the buffer if necessary */
125 if (buffer_compact(buffer
))
128 /* Increase the size of the buffer and retry. */
129 newlen
= roundup(buffer
->alloc
+ len
, BUFFER_ALLOCSZ
);
130 if (newlen
> BUFFER_MAX_LEN
)
131 fatal("buffer_append_space: alloc %u not supported",
133 buffer
->buf
= xrealloc(buffer
->buf
, 1, newlen
);
134 buffer
->alloc
= newlen
;
140 * Check whether an allocation of 'len' will fit in the buffer
141 * This must follow the same math as buffer_append_space
144 buffer_check_alloc(Buffer
*buffer
, u_int len
)
146 if (buffer
->offset
== buffer
->end
) {
151 if (buffer
->end
+ len
< buffer
->alloc
)
153 if (buffer_compact(buffer
))
155 if (roundup(buffer
->alloc
+ len
, BUFFER_ALLOCSZ
) <= BUFFER_MAX_LEN
)
160 /* Returns the number of bytes of data in the buffer. */
163 buffer_len(const Buffer
*buffer
)
165 return buffer
->end
- buffer
->offset
;
168 /* Gets data from the beginning of the buffer. */
171 buffer_get_ret(Buffer
*buffer
, void *buf
, u_int len
)
173 if (len
> buffer
->end
- buffer
->offset
) {
174 error("buffer_get_ret: trying to get more bytes %d than in buffer %d",
175 len
, buffer
->end
- buffer
->offset
);
178 memcpy(buf
, buffer
->buf
+ buffer
->offset
, len
);
179 buffer
->offset
+= len
;
184 buffer_get(Buffer
*buffer
, void *buf
, u_int len
)
186 if (buffer_get_ret(buffer
, buf
, len
) == -1)
187 fatal("buffer_get: buffer error");
190 /* Consumes the given number of bytes from the beginning of the buffer. */
193 buffer_consume_ret(Buffer
*buffer
, u_int bytes
)
195 if (bytes
> buffer
->end
- buffer
->offset
) {
196 error("buffer_consume_ret: trying to get more bytes than in buffer");
199 buffer
->offset
+= bytes
;
204 buffer_consume(Buffer
*buffer
, u_int bytes
)
206 if (buffer_consume_ret(buffer
, bytes
) == -1)
207 fatal("buffer_consume: buffer error");
210 /* Consumes the given number of bytes from the end of the buffer. */
213 buffer_consume_end_ret(Buffer
*buffer
, u_int bytes
)
215 if (bytes
> buffer
->end
- buffer
->offset
)
217 buffer
->end
-= bytes
;
222 buffer_consume_end(Buffer
*buffer
, u_int bytes
)
224 if (buffer_consume_end_ret(buffer
, bytes
) == -1)
225 fatal("buffer_consume_end: trying to get more bytes than in buffer");
228 /* Returns a pointer to the first used byte in the buffer. */
231 buffer_ptr(const Buffer
*buffer
)
233 return buffer
->buf
+ buffer
->offset
;
236 /* Dumps the contents of the buffer to stderr. */
239 buffer_dump(const Buffer
*buffer
)
242 u_char
*ucp
= buffer
->buf
;
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
, " ");
251 fprintf(stderr
, "\r\n");