Annotation of src/usr.bin/ssh/buffer.c, Revision 1.35
1.35 ! djm 1: /* $OpenBSD: buffer.c,v 1.34 2013/11/08 11:15:19 dtucker Exp $ */
1.1 deraadt 2: /*
1.3 deraadt 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).
1.6 markus 7: *
1.8 deraadt 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".
1.3 deraadt 13: */
1.1 deraadt 14:
1.29 stevesk 15: #include <sys/param.h>
1.28 stevesk 16:
1.30 stevesk 17: #include <stdio.h>
1.28 stevesk 18: #include <string.h>
1.31 deraadt 19: #include <stdarg.h>
1.34 dtucker 20: #include <stdlib.h>
1.1 deraadt 21:
22: #include "xmalloc.h"
23: #include "buffer.h"
1.10 markus 24: #include "log.h"
1.1 deraadt 25:
1.27 djm 26: #define BUFFER_MAX_CHUNK 0x100000
27: #define BUFFER_MAX_LEN 0xa00000
28: #define BUFFER_ALLOCSZ 0x008000
29:
1.1 deraadt 30: /* Initializes the buffer structure. */
31:
1.6 markus 32: void
1.2 markus 33: buffer_init(Buffer *buffer)
1.1 deraadt 34: {
1.18 markus 35: const u_int len = 4096;
36:
37: buffer->alloc = 0;
38: buffer->buf = xmalloc(len);
39: buffer->alloc = len;
1.2 markus 40: buffer->offset = 0;
41: buffer->end = 0;
1.1 deraadt 42: }
43:
44: /* Frees any memory used for the buffer. */
45:
1.6 markus 46: void
1.2 markus 47: buffer_free(Buffer *buffer)
1.1 deraadt 48: {
1.18 markus 49: if (buffer->alloc > 0) {
1.35 ! djm 50: explicit_bzero(buffer->buf, buffer->alloc);
1.19 markus 51: buffer->alloc = 0;
1.33 djm 52: free(buffer->buf);
1.18 markus 53: }
1.1 deraadt 54: }
55:
1.4 markus 56: /*
57: * Clears any data from the buffer, making it empty. This does not actually
58: * zero the memory.
59: */
1.1 deraadt 60:
1.6 markus 61: void
1.2 markus 62: buffer_clear(Buffer *buffer)
1.1 deraadt 63: {
1.2 markus 64: buffer->offset = 0;
65: buffer->end = 0;
1.1 deraadt 66: }
67:
68: /* Appends data to the buffer, expanding it if necessary. */
69:
1.6 markus 70: void
1.14 stevesk 71: buffer_append(Buffer *buffer, const void *data, u_int len)
1.1 deraadt 72: {
1.14 stevesk 73: void *p;
74: p = buffer_append_space(buffer, len);
75: memcpy(p, data, len);
1.1 deraadt 76: }
77:
1.27 djm 78: static int
79: buffer_compact(Buffer *buffer)
80: {
81: /*
82: * If the buffer is quite empty, but all data is at the end, move the
83: * data to the beginning.
84: */
85: if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) {
86: memmove(buffer->buf, buffer->buf + buffer->offset,
87: buffer->end - buffer->offset);
88: buffer->end -= buffer->offset;
89: buffer->offset = 0;
90: return (1);
91: }
92: return (0);
93: }
94:
1.4 markus 95: /*
96: * Appends space to the buffer, expanding the buffer if necessary. This does
97: * not actually copy the data into the buffer, but instead returns a pointer
98: * to the allocated region.
99: */
1.1 deraadt 100:
1.14 stevesk 101: void *
102: buffer_append_space(Buffer *buffer, u_int len)
1.1 deraadt 103: {
1.17 deraadt 104: u_int newlen;
1.14 stevesk 105: void *p;
106:
1.23 markus 107: if (len > BUFFER_MAX_CHUNK)
1.16 markus 108: fatal("buffer_append_space: len %u not supported", len);
109:
1.2 markus 110: /* If the buffer is empty, start using it from the beginning. */
111: if (buffer->offset == buffer->end) {
112: buffer->offset = 0;
113: buffer->end = 0;
114: }
115: restart:
116: /* If there is enough space to store all data, store it now. */
117: if (buffer->end + len < buffer->alloc) {
1.14 stevesk 118: p = buffer->buf + buffer->end;
1.2 markus 119: buffer->end += len;
1.14 stevesk 120: return p;
1.2 markus 121: }
1.27 djm 122:
123: /* Compact data back to the start of the buffer if necessary */
124: if (buffer_compact(buffer))
1.2 markus 125: goto restart;
1.27 djm 126:
1.2 markus 127: /* Increase the size of the buffer and retry. */
1.27 djm 128: newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ);
1.23 markus 129: if (newlen > BUFFER_MAX_LEN)
1.16 markus 130: fatal("buffer_append_space: alloc %u not supported",
1.17 deraadt 131: newlen);
1.25 djm 132: buffer->buf = xrealloc(buffer->buf, 1, newlen);
1.17 deraadt 133: buffer->alloc = newlen;
1.2 markus 134: goto restart;
1.14 stevesk 135: /* NOTREACHED */
1.27 djm 136: }
137:
138: /*
139: * Check whether an allocation of 'len' will fit in the buffer
140: * This must follow the same math as buffer_append_space
141: */
142: int
143: buffer_check_alloc(Buffer *buffer, u_int len)
144: {
145: if (buffer->offset == buffer->end) {
146: buffer->offset = 0;
147: buffer->end = 0;
148: }
149: restart:
150: if (buffer->end + len < buffer->alloc)
151: return (1);
152: if (buffer_compact(buffer))
153: goto restart;
154: if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN)
155: return (1);
156: return (0);
1.1 deraadt 157: }
158:
159: /* Returns the number of bytes of data in the buffer. */
160:
1.9 markus 161: u_int
1.32 djm 162: buffer_len(const Buffer *buffer)
1.1 deraadt 163: {
1.2 markus 164: return buffer->end - buffer->offset;
1.1 deraadt 165: }
166:
167: /* Gets data from the beginning of the buffer. */
168:
1.22 djm 169: int
170: buffer_get_ret(Buffer *buffer, void *buf, u_int len)
1.1 deraadt 171: {
1.22 djm 172: if (len > buffer->end - buffer->offset) {
173: error("buffer_get_ret: trying to get more bytes %d than in buffer %d",
1.11 markus 174: len, buffer->end - buffer->offset);
1.22 djm 175: return (-1);
176: }
1.2 markus 177: memcpy(buf, buffer->buf + buffer->offset, len);
178: buffer->offset += len;
1.22 djm 179: return (0);
180: }
181:
182: void
183: buffer_get(Buffer *buffer, void *buf, u_int len)
184: {
185: if (buffer_get_ret(buffer, buf, len) == -1)
186: fatal("buffer_get: buffer error");
1.1 deraadt 187: }
188:
189: /* Consumes the given number of bytes from the beginning of the buffer. */
190:
1.22 djm 191: int
192: buffer_consume_ret(Buffer *buffer, u_int bytes)
193: {
194: if (bytes > buffer->end - buffer->offset) {
195: error("buffer_consume_ret: trying to get more bytes than in buffer");
196: return (-1);
197: }
198: buffer->offset += bytes;
199: return (0);
200: }
201:
1.6 markus 202: void
1.9 markus 203: buffer_consume(Buffer *buffer, u_int bytes)
1.1 deraadt 204: {
1.22 djm 205: if (buffer_consume_ret(buffer, bytes) == -1)
206: fatal("buffer_consume: buffer error");
1.2 markus 207: }
1.1 deraadt 208:
209: /* Consumes the given number of bytes from the end of the buffer. */
210:
1.22 djm 211: int
212: buffer_consume_end_ret(Buffer *buffer, u_int bytes)
213: {
214: if (bytes > buffer->end - buffer->offset)
215: return (-1);
216: buffer->end -= bytes;
217: return (0);
218: }
219:
1.6 markus 220: void
1.9 markus 221: buffer_consume_end(Buffer *buffer, u_int bytes)
1.1 deraadt 222: {
1.22 djm 223: if (buffer_consume_end_ret(buffer, bytes) == -1)
1.5 markus 224: fatal("buffer_consume_end: trying to get more bytes than in buffer");
1.2 markus 225: }
1.1 deraadt 226:
227: /* Returns a pointer to the first used byte in the buffer. */
228:
1.14 stevesk 229: void *
1.32 djm 230: buffer_ptr(const Buffer *buffer)
1.1 deraadt 231: {
1.2 markus 232: return buffer->buf + buffer->offset;
1.1 deraadt 233: }
234:
235: /* Dumps the contents of the buffer to stderr. */
236:
1.6 markus 237: void
1.32 djm 238: buffer_dump(const Buffer *buffer)
1.1 deraadt 239: {
1.20 markus 240: u_int i;
1.15 stevesk 241: u_char *ucp = buffer->buf;
1.2 markus 242:
1.13 markus 243: for (i = buffer->offset; i < buffer->end; i++) {
244: fprintf(stderr, "%02x", ucp[i]);
245: if ((i-buffer->offset)%16==15)
246: fprintf(stderr, "\r\n");
247: else if ((i-buffer->offset)%2==1)
248: fprintf(stderr, " ");
249: }
1.12 markus 250: fprintf(stderr, "\r\n");
1.1 deraadt 251: }