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