buffer.c revision 147001
1178355Ssam/* 2178355Ssam * Author: Tatu Ylonen <ylo@cs.hut.fi> 3178355Ssam * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4208060Sdougb * All rights reserved 5178355Ssam * Functions for manipulating fifo buffers (that can grow if needed). 6178355Ssam * 7178355Ssam * As far as I am concerned, the code I have written for this software 8178355Ssam * can be used freely for any purpose. Any derived versions of this 9178355Ssam * software must be clearly marked as such, and if the derived work is 10178355Ssam * incompatible with the protocol description in the RFC file, it must be 11178355Ssam * called by a name other than "ssh" or "Secure Shell". 12178355Ssam */ 13208060Sdougb 14178355Ssam#include "includes.h" 15178355SsamRCSID("$OpenBSD: buffer.c,v 1.23 2005/03/14 11:46:56 markus Exp $"); 16178355Ssam 17178355Ssam#include "xmalloc.h" 18178355Ssam#include "buffer.h" 19178355Ssam#include "log.h" 20178355Ssam 21178355Ssam/* Initializes the buffer structure. */ 22178355Ssam 23178355Ssamvoid 24208060Sdougbbuffer_init(Buffer *buffer) 25178355Ssam{ 26178355Ssam const u_int len = 4096; 27178355Ssam 28178355Ssam buffer->alloc = 0; 29178355Ssam buffer->buf = xmalloc(len); 30178355Ssam buffer->alloc = len; 31178355Ssam buffer->offset = 0; 32178355Ssam buffer->end = 0; 33178355Ssam} 34178355Ssam 35178355Ssam/* Frees any memory used for the buffer. */ 36178355Ssam 37178355Ssamvoid 38178355Ssambuffer_free(Buffer *buffer) 39178355Ssam{ 40178355Ssam if (buffer->alloc > 0) { 41178355Ssam memset(buffer->buf, 0, buffer->alloc); 42186106Ssam buffer->alloc = 0; 43178355Ssam xfree(buffer->buf); 44178355Ssam } 45178355Ssam} 46178355Ssam 47178355Ssam/* 48178355Ssam * Clears any data from the buffer, making it empty. This does not actually 49178355Ssam * zero the memory. 50178355Ssam */ 51178355Ssam 52178355Ssamvoid 53178355Ssambuffer_clear(Buffer *buffer) 54178355Ssam{ 55178355Ssam buffer->offset = 0; 56178355Ssam buffer->end = 0; 57178355Ssam} 58178355Ssam 59178355Ssam/* Appends data to the buffer, expanding it if necessary. */ 60178355Ssam 61178355Ssamvoid 62178355Ssambuffer_append(Buffer *buffer, const void *data, u_int len) 63178355Ssam{ 64178355Ssam void *p; 65178355Ssam p = buffer_append_space(buffer, len); 66178355Ssam memcpy(p, data, len); 67178355Ssam} 68178355Ssam 69178355Ssam/* 70178355Ssam * Appends space to the buffer, expanding the buffer if necessary. This does 71178355Ssam * not actually copy the data into the buffer, but instead returns a pointer 72178355Ssam * to the allocated region. 73178355Ssam */ 74178355Ssam 75178355Ssamvoid * 76178355Ssambuffer_append_space(Buffer *buffer, u_int len) 77178355Ssam{ 78178355Ssam u_int newlen; 79178355Ssam void *p; 80178355Ssam 81178355Ssam if (len > BUFFER_MAX_CHUNK) 82178355Ssam fatal("buffer_append_space: len %u not supported", len); 83178355Ssam 84178355Ssam /* If the buffer is empty, start using it from the beginning. */ 85178355Ssam if (buffer->offset == buffer->end) { 86223497Sadrian buffer->offset = 0; 87178355Ssam buffer->end = 0; 88178355Ssam } 89178355Ssamrestart: 90178355Ssam /* If there is enough space to store all data, store it now. */ 91178355Ssam if (buffer->end + len < buffer->alloc) { 92178355Ssam p = buffer->buf + buffer->end; 93178355Ssam buffer->end += len; 94178355Ssam return p; 95178355Ssam } 96178355Ssam /* 97178355Ssam * If the buffer is quite empty, but all data is at the end, move the 98178355Ssam * data to the beginning and retry. 99223498Sadrian */ 100178355Ssam if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) { 101178355Ssam memmove(buffer->buf, buffer->buf + buffer->offset, 102178355Ssam buffer->end - buffer->offset); 103178355Ssam buffer->end -= buffer->offset; 104178355Ssam buffer->offset = 0; 105178355Ssam goto restart; 106178355Ssam } 107178355Ssam /* Increase the size of the buffer and retry. */ 108178355Ssam 109223498Sadrian newlen = buffer->alloc + len + 32768; 110178355Ssam if (newlen > BUFFER_MAX_LEN) 111178355Ssam fatal("buffer_append_space: alloc %u not supported", 112178355Ssam newlen); 113178355Ssam buffer->buf = xrealloc(buffer->buf, newlen); 114178355Ssam buffer->alloc = newlen; 115178355Ssam goto restart; 116178355Ssam /* NOTREACHED */ 117178355Ssam} 118178355Ssam 119178355Ssam/* Returns the number of bytes of data in the buffer. */ 120178355Ssam 121178355Ssamu_int 122178355Ssambuffer_len(Buffer *buffer) 123178355Ssam{ 124178355Ssam return buffer->end - buffer->offset; 125178355Ssam} 126178355Ssam 127178355Ssam/* Gets data from the beginning of the buffer. */ 128178355Ssam 129178355Ssamint 130178355Ssambuffer_get_ret(Buffer *buffer, void *buf, u_int len) 131178355Ssam{ 132178355Ssam if (len > buffer->end - buffer->offset) { 133178355Ssam error("buffer_get_ret: trying to get more bytes %d than in buffer %d", 134178355Ssam len, buffer->end - buffer->offset); 135178355Ssam return (-1); 136178355Ssam } 137178355Ssam memcpy(buf, buffer->buf + buffer->offset, len); 138178355Ssam buffer->offset += len; 139178355Ssam return (0); 140178355Ssam} 141223496Sadrian 142223496Sadrianvoid 143223496Sadrianbuffer_get(Buffer *buffer, void *buf, u_int len) 144223496Sadrian{ 145223496Sadrian if (buffer_get_ret(buffer, buf, len) == -1) 146223496Sadrian fatal("buffer_get: buffer error"); 147178355Ssam} 148178355Ssam 149178355Ssam/* Consumes the given number of bytes from the beginning of the buffer. */ 150178355Ssam 151178355Ssamint 152178355Ssambuffer_consume_ret(Buffer *buffer, u_int bytes) 153178355Ssam{ 154178355Ssam if (bytes > buffer->end - buffer->offset) { 155178355Ssam error("buffer_consume_ret: trying to get more bytes than in buffer"); 156178355Ssam return (-1); 157178355Ssam } 158178355Ssam buffer->offset += bytes; 159178355Ssam return (0); 160178355Ssam} 161178355Ssam 162178355Ssamvoid 163178355Ssambuffer_consume(Buffer *buffer, u_int bytes) 164178355Ssam{ 165178355Ssam if (buffer_consume_ret(buffer, bytes) == -1) 166178355Ssam fatal("buffer_consume: buffer error"); 167178355Ssam} 168178355Ssam 169178355Ssam/* Consumes the given number of bytes from the end of the buffer. */ 170178355Ssam 171178355Ssamint 172178355Ssambuffer_consume_end_ret(Buffer *buffer, u_int bytes) 173178355Ssam{ 174178355Ssam if (bytes > buffer->end - buffer->offset) 175178355Ssam return (-1); 176178355Ssam buffer->end -= bytes; 177178355Ssam return (0); 178178355Ssam} 179178355Ssam 180178355Ssamvoid 181178355Ssambuffer_consume_end(Buffer *buffer, u_int bytes) 182178355Ssam{ 183178355Ssam if (buffer_consume_end_ret(buffer, bytes) == -1) 184178355Ssam fatal("buffer_consume_end: trying to get more bytes than in buffer"); 185223496Sadrian} 186223496Sadrian 187223496Sadrian/* Returns a pointer to the first used byte in the buffer. */ 188223496Sadrian 189223496Sadrianvoid * 190223496Sadrianbuffer_ptr(Buffer *buffer) 191223496Sadrian{ 192223496Sadrian return buffer->buf + buffer->offset; 193223496Sadrian} 194223496Sadrian 195223496Sadrian/* Dumps the contents of the buffer to stderr. */ 196223496Sadrian 197223496Sadrianvoid 198223496Sadrianbuffer_dump(Buffer *buffer) 199178355Ssam{ 200178355Ssam u_int i; 201178355Ssam u_char *ucp = buffer->buf; 202178355Ssam 203178355Ssam for (i = buffer->offset; i < buffer->end; i++) { 204178355Ssam fprintf(stderr, "%02x", ucp[i]); 205178355Ssam if ((i-buffer->offset)%16==15) 206178355Ssam fprintf(stderr, "\r\n"); 207178355Ssam else if ((i-buffer->offset)%2==1) 208178355Ssam fprintf(stderr, " "); 209178355Ssam } 210178355Ssam fprintf(stderr, "\r\n"); 211178355Ssam} 212178355Ssam