1 /* 2 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * All rights reserved 5 * Functions for manipulating fifo buffers (that can grow if needed). 6 * 7 * As far as I am concerned, the code I have written for this software 8 * can be used freely for any purpose. Any derived versions of this 9 * software must be clearly marked as such, and if the derived work is 10 * incompatible with the protocol description in the RFC file, it must be 11 * called by a name other than "ssh" or "Secure Shell". 12 */ 13 14 #include "includes.h" 15 RCSID("$OpenBSD: buffer.c,v 1.23 2005/03/14 11:46:56 markus Exp $"); 16 17 #pragma ident "%Z%%M% %I% %E% SMI" 18 19 #include "xmalloc.h" 20 #include "buffer.h" 21 #include "log.h" 22 23 /* Initializes the buffer structure. */ 24 25 void 26 buffer_init(Buffer *buffer) 27 { 28 const u_int len = 4096; 29 30 buffer->alloc = 0; 31 buffer->buf = xmalloc(len); 32 buffer->alloc = len; 33 buffer->offset = 0; 34 buffer->end = 0; 35 } 36 37 /* Frees any memory used for the buffer. */ 38 39 void 40 buffer_free(Buffer *buffer) 41 { 42 if (buffer->alloc > 0) { 43 memset(buffer->buf, 0, buffer->alloc); 44 buffer->alloc = 0; 45 xfree(buffer->buf); 46 } 47 } 48 49 /* 50 * Clears any data from the buffer, making it empty. This does not actually 51 * zero the memory. 52 */ 53 54 void 55 buffer_clear(Buffer *buffer) 56 { 57 buffer->offset = 0; 58 buffer->end = 0; 59 } 60 61 /* Appends data to the buffer, expanding it if necessary. */ 62 63 void 64 buffer_append(Buffer *buffer, const void *data, u_int len) 65 { 66 void *p; 67 p = buffer_append_space(buffer, len); 68 memcpy(p, data, len); 69 } 70 71 /* 72 * Appends space to the buffer, expanding the buffer if necessary. This does 73 * not actually copy the data into the buffer, but instead returns a pointer 74 * to the allocated region. 75 */ 76 77 void * 78 buffer_append_space(Buffer *buffer, u_int len) 79 { 80 u_int newlen; 81 void *p; 82 83 if (len > BUFFER_MAX_CHUNK) 84 fatal("buffer_append_space: len %u not supported", len); 85 86 /* If the buffer is empty, start using it from the beginning. */ 87 if (buffer->offset == buffer->end) { 88 buffer->offset = 0; 89 buffer->end = 0; 90 } 91 restart: 92 /* If there is enough space to store all data, store it now. */ 93 if (buffer->end + len < buffer->alloc) { 94 p = buffer->buf + buffer->end; 95 buffer->end += len; 96 return p; 97 } 98 /* 99 * If the buffer is quite empty, but all data is at the end, move the 100 * data to the beginning and retry. 101 */ 102 if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) { 103 memmove(buffer->buf, buffer->buf + buffer->offset, 104 buffer->end - buffer->offset); 105 buffer->end -= buffer->offset; 106 buffer->offset = 0; 107 goto restart; 108 } 109 /* Increase the size of the buffer and retry. */ 110 111 newlen = buffer->alloc + len + 32768; 112 if (newlen > BUFFER_MAX_LEN) 113 fatal("buffer_append_space: alloc %u not supported", 114 newlen); 115 buffer->buf = xrealloc(buffer->buf, newlen); 116 buffer->alloc = newlen; 117 goto restart; 118 /* NOTREACHED */ 119 } 120 121 /* Returns the number of bytes of data in the buffer. */ 122 123 u_int 124 buffer_len(Buffer *buffer) 125 { 126 return buffer->end - buffer->offset; 127 } 128 129 /* Gets data from the beginning of the buffer. */ 130 131 int 132 buffer_get_ret(Buffer *buffer, void *buf, u_int len) 133 { 134 if (len > buffer->end - buffer->offset) { 135 error("buffer_get_ret: trying to get more bytes %d than in buffer %d", 136 len, buffer->end - buffer->offset); 137 return (-1); 138 } 139 memcpy(buf, buffer->buf + buffer->offset, len); 140 buffer->offset += len; 141 return (0); 142 } 143 144 void 145 buffer_get(Buffer *buffer, void *buf, u_int len) 146 { 147 if (buffer_get_ret(buffer, buf, len) == -1) 148 fatal("buffer_get: buffer error"); 149 } 150 151 /* Consumes the given number of bytes from the beginning of the buffer. */ 152 153 int 154 buffer_consume_ret(Buffer *buffer, u_int bytes) 155 { 156 if (bytes > buffer->end - buffer->offset) { 157 error("buffer_consume_ret: trying to get more bytes than in buffer"); 158 return (-1); 159 } 160 buffer->offset += bytes; 161 return (0); 162 } 163 164 void 165 buffer_consume(Buffer *buffer, u_int bytes) 166 { 167 if (buffer_consume_ret(buffer, bytes) == -1) 168 fatal("buffer_consume: buffer error"); 169 } 170 171 /* Consumes the given number of bytes from the end of the buffer. */ 172 173 int 174 buffer_consume_end_ret(Buffer *buffer, u_int bytes) 175 { 176 if (bytes > buffer->end - buffer->offset) 177 return (-1); 178 buffer->end -= bytes; 179 return (0); 180 } 181 182 void 183 buffer_consume_end(Buffer *buffer, u_int bytes) 184 { 185 if (buffer_consume_end_ret(buffer, bytes) == -1) 186 fatal("buffer_consume_end: trying to get more bytes than in buffer"); 187 } 188 189 /* Returns a pointer to the first used byte in the buffer. */ 190 191 void * 192 buffer_ptr(Buffer *buffer) 193 { 194 return buffer->buf + buffer->offset; 195 } 196 197 /* Dumps the contents of the buffer to stderr. */ 198 199 void 200 buffer_dump(Buffer *buffer) 201 { 202 u_int i; 203 u_char *ucp = buffer->buf; 204 205 for (i = buffer->offset; i < buffer->end; i++) { 206 fprintf(stderr, "%02x", ucp[i]); 207 if ((i-buffer->offset)%16==15) 208 fprintf(stderr, "\r\n"); 209 else if ((i-buffer->offset)%2==1) 210 fprintf(stderr, " "); 211 } 212 fprintf(stderr, "\r\n"); 213 } 214