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.16 2002/06/26 08:54:18 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 xfree(buffer->buf); 45 } 46 } 47 48 /* 49 * Clears any data from the buffer, making it empty. This does not actually 50 * zero the memory. 51 */ 52 53 void 54 buffer_clear(Buffer *buffer) 55 { 56 buffer->offset = 0; 57 buffer->end = 0; 58 } 59 60 /* Appends data to the buffer, expanding it if necessary. */ 61 62 void 63 buffer_append(Buffer *buffer, const void *data, u_int len) 64 { 65 void *p; 66 p = buffer_append_space(buffer, len); 67 memcpy(p, data, len); 68 } 69 70 /* 71 * Appends space to the buffer, expanding the buffer if necessary. This does 72 * not actually copy the data into the buffer, but instead returns a pointer 73 * to the allocated region. 74 */ 75 76 void * 77 buffer_append_space(Buffer *buffer, u_int len) 78 { 79 u_int newlen; 80 void *p; 81 82 if (len > 0x100000) 83 fatal("buffer_append_space: len %u not supported", len); 84 85 /* If the buffer is empty, start using it from the beginning. */ 86 if (buffer->offset == buffer->end) { 87 buffer->offset = 0; 88 buffer->end = 0; 89 } 90 restart: 91 /* If there is enough space to store all data, store it now. */ 92 if (buffer->end + len < buffer->alloc) { 93 p = buffer->buf + buffer->end; 94 buffer->end += len; 95 return p; 96 } 97 /* 98 * If the buffer is quite empty, but all data is at the end, move the 99 * data to the beginning and retry. 100 */ 101 if (buffer->offset > buffer->alloc / 2) { 102 memmove(buffer->buf, buffer->buf + buffer->offset, 103 buffer->end - buffer->offset); 104 buffer->end -= buffer->offset; 105 buffer->offset = 0; 106 goto restart; 107 } 108 /* Increase the size of the buffer and retry. */ 109 110 newlen = buffer->alloc + len + 32768; 111 if (newlen > 0xa00000) 112 fatal("buffer_append_space: alloc %u not supported", 113 newlen); 114 buffer->buf = xrealloc(buffer->buf, newlen); 115 buffer->alloc = newlen; 116 goto restart; 117 /* NOTREACHED */ 118 } 119 120 /* Returns the number of bytes of data in the buffer. */ 121 122 u_int 123 buffer_len(Buffer *buffer) 124 { 125 return buffer->end - buffer->offset; 126 } 127 128 /* Gets data from the beginning of the buffer. */ 129 130 void 131 buffer_get(Buffer *buffer, void *buf, u_int len) 132 { 133 if (len > buffer->end - buffer->offset) 134 fatal("buffer_get: trying to get more bytes %d than in buffer %d", 135 len, buffer->end - buffer->offset); 136 memcpy(buf, buffer->buf + buffer->offset, len); 137 buffer->offset += len; 138 } 139 140 /* Consumes the given number of bytes from the beginning of the buffer. */ 141 142 void 143 buffer_consume(Buffer *buffer, u_int bytes) 144 { 145 if (bytes > buffer->end - buffer->offset) 146 fatal("buffer_consume: trying to get more bytes than in buffer"); 147 buffer->offset += bytes; 148 } 149 150 /* Consumes the given number of bytes from the end of the buffer. */ 151 152 void 153 buffer_consume_end(Buffer *buffer, u_int bytes) 154 { 155 if (bytes > buffer->end - buffer->offset) 156 fatal("buffer_consume_end: trying to get more bytes than in buffer"); 157 buffer->end -= bytes; 158 } 159 160 /* Returns a pointer to the first used byte in the buffer. */ 161 162 void * 163 buffer_ptr(Buffer *buffer) 164 { 165 return buffer->buf + buffer->offset; 166 } 167 168 /* Dumps the contents of the buffer to stderr. */ 169 170 void 171 buffer_dump(Buffer *buffer) 172 { 173 int i; 174 u_char *ucp = buffer->buf; 175 176 for (i = buffer->offset; i < buffer->end; i++) { 177 fprintf(stderr, "%02x", ucp[i]); 178 if ((i-buffer->offset)%16==15) 179 fprintf(stderr, "\r\n"); 180 else if ((i-buffer->offset)%2==1) 181 fprintf(stderr, " "); 182 } 183 fprintf(stderr, "\r\n"); 184 } 185