buffer.c revision 126274
113044Sasami/* 2116111Sphk * Author: Tatu Ylonen <ylo@cs.hut.fi> 313044Sasami * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 413044Sasami * All rights reserved 513044Sasami * Functions for manipulating fifo buffers (that can grow if needed). 613044Sasami * 713044Sasami * As far as I am concerned, the code I have written for this software 813044Sasami * can be used freely for any purpose. Any derived versions of this 913044Sasami * software must be clearly marked as such, and if the derived work is 1013044Sasami * incompatible with the protocol description in the RFC file, it must be 1113044Sasami * called by a name other than "ssh" or "Secure Shell". 1213044Sasami */ 1313044Sasami 1413044Sasami#include "includes.h" 1513044SasamiRCSID("$OpenBSD: buffer.c,v 1.21 2003/11/21 11:57:03 djm Exp $"); 1613044Sasami 1713044Sasami#include "xmalloc.h" 1813044Sasami#include "buffer.h" 1913044Sasami#include "log.h" 2013044Sasami 2113044Sasami/* Initializes the buffer structure. */ 2213044Sasami 2313044Sasamivoid 2413044Sasamibuffer_init(Buffer *buffer) 2513044Sasami{ 2613044Sasami const u_int len = 4096; 2713044Sasami 2813044Sasami buffer->alloc = 0; 2913044Sasami buffer->buf = xmalloc(len); 3013044Sasami buffer->alloc = len; 3113044Sasami buffer->offset = 0; 3213044Sasami buffer->end = 0; 3313044Sasami} 34114589Sobrien 35114589Sobrien/* Frees any memory used for the buffer. */ 3636628Scharnier 3713044Sasamivoid 3848568Sbillfbuffer_free(Buffer *buffer) 3945329Speter{ 4013044Sasami if (buffer->alloc > 0) { 4113044Sasami memset(buffer->buf, 0, buffer->alloc); 4213044Sasami buffer->alloc = 0; 4313044Sasami xfree(buffer->buf); 4469793Sobrien } 4513044Sasami} 4613044Sasami 4713044Sasami/* 4813044Sasami * Clears any data from the buffer, making it empty. This does not actually 49115730Sphk * zero the memory. 5013044Sasami */ 51116111Sphk 52116111Sphkvoid 5313044Sasamibuffer_clear(Buffer *buffer) 5413044Sasami{ 5513044Sasami buffer->offset = 0; 5613044Sasami buffer->end = 0; 5713044Sasami} 58109417Sphk 5913044Sasami/* Appends data to the buffer, expanding it if necessary. */ 6013044Sasami 61109417Sphkvoid 62116111Sphkbuffer_append(Buffer *buffer, const void *data, u_int len) 6313044Sasami{ 6413044Sasami void *p; 65116111Sphk p = buffer_append_space(buffer, len); 6613762Sasami memcpy(p, data, len); 67116111Sphk} 68116111Sphk 6913044Sasami/* 7013044Sasami * Appends space to the buffer, expanding the buffer if necessary. This does 7113044Sasami * not actually copy the data into the buffer, but instead returns a pointer 7213044Sasami * to the allocated region. 7313044Sasami */ 7413044Sasami 7513044Sasamivoid * 7613044Sasamibuffer_append_space(Buffer *buffer, u_int len) 7713044Sasami{ 7892539Simp u_int newlen; 7992539Simp void *p; 8092539Simp 8192539Simp if (len > 0x100000) 82109417Sphk fatal("buffer_append_space: len %u not supported", len); 8392539Simp 8413044Sasami /* If the buffer is empty, start using it from the beginning. */ 8513044Sasami if (buffer->offset == buffer->end) { 8692539Simp buffer->offset = 0; 8713044Sasami buffer->end = 0; 8813044Sasami } 8913044Sasamirestart: 9083329Sru /* If there is enough space to store all data, store it now. */ 9113044Sasami if (buffer->end + len < buffer->alloc) { 9213044Sasami p = buffer->buf + buffer->end; 9313044Sasami buffer->end += len; 9413044Sasami return p; 9513044Sasami } 9613044Sasami /* 9713044Sasami * If the buffer is quite empty, but all data is at the end, move the 9813044Sasami * data to the beginning and retry. 9913044Sasami */ 10013044Sasami if (buffer->offset > buffer->alloc / 2) { 10113044Sasami memmove(buffer->buf, buffer->buf + buffer->offset, 10213044Sasami buffer->end - buffer->offset); 10313044Sasami buffer->end -= buffer->offset; 10413044Sasami buffer->offset = 0; 10513044Sasami goto restart; 10613044Sasami } 10713044Sasami /* Increase the size of the buffer and retry. */ 10813044Sasami 10913044Sasami newlen = buffer->alloc + len + 32768; 11013044Sasami if (newlen > 0xa00000) 11113044Sasami fatal("buffer_append_space: alloc %u not supported", 11213044Sasami newlen); 11313044Sasami buffer->buf = xrealloc(buffer->buf, newlen); 11413044Sasami buffer->alloc = newlen; 11513044Sasami goto restart; 11613044Sasami /* NOTREACHED */ 11713044Sasami} 11813044Sasami 11913044Sasami/* Returns the number of bytes of data in the buffer. */ 12013044Sasami 12113044Sasamiu_int 12213044Sasamibuffer_len(Buffer *buffer) 12313044Sasami{ 12413044Sasami return buffer->end - buffer->offset; 12513044Sasami} 12613044Sasami 12713044Sasami/* Gets data from the beginning of the buffer. */ 12813044Sasami 12913044Sasamivoid 13013044Sasamibuffer_get(Buffer *buffer, void *buf, u_int len) 13113044Sasami{ 13213044Sasami if (len > buffer->end - buffer->offset) 13313044Sasami fatal("buffer_get: trying to get more bytes %d than in buffer %d", 134116111Sphk len, buffer->end - buffer->offset); 13545329Speter memcpy(buf, buffer->buf + buffer->offset, len); 136116126Sphk buffer->offset += len; 137116126Sphk} 13845329Speter 13945329Speter/* Consumes the given number of bytes from the beginning of the buffer. */ 14013044Sasami 14113044Sasamivoid 14213044Sasamibuffer_consume(Buffer *buffer, u_int bytes) 14313044Sasami{ 14413044Sasami if (bytes > buffer->end - buffer->offset) 14513044Sasami fatal("buffer_consume: trying to get more bytes than in buffer"); 14613044Sasami buffer->offset += bytes; 14713044Sasami} 14813044Sasami 14913044Sasami/* Consumes the given number of bytes from the end of the buffer. */ 15013044Sasami 15113044Sasamivoid 15213044Sasamibuffer_consume_end(Buffer *buffer, u_int bytes) 15313044Sasami{ 15413044Sasami if (bytes > buffer->end - buffer->offset) 15513044Sasami fatal("buffer_consume_end: trying to get more bytes than in buffer"); 15636628Scharnier buffer->end -= bytes; 15713044Sasami} 15813044Sasami 15913044Sasami/* Returns a pointer to the first used byte in the buffer. */ 16092539Simp 16113044Sasamivoid * 162116111Sphkbuffer_ptr(Buffer *buffer) 163116111Sphk{ 164116111Sphk return buffer->buf + buffer->offset; 165116111Sphk} 166116111Sphk 167116111Sphk/* Dumps the contents of the buffer to stderr. */ 16813044Sasami 16913044Sasamivoid 17013044Sasamibuffer_dump(Buffer *buffer) 17113044Sasami{ 17213044Sasami u_int i; 173116111Sphk u_char *ucp = buffer->buf; 17413044Sasami 17513044Sasami for (i = buffer->offset; i < buffer->end; i++) { 176109472Sphk fprintf(stderr, "%02x", ucp[i]); 17713044Sasami if ((i-buffer->offset)%16==15) 17813044Sasami fprintf(stderr, "\r\n"); 17913044Sasami else if ((i-buffer->offset)%2==1) 18013044Sasami fprintf(stderr, " "); 181116111Sphk } 182116111Sphk fprintf(stderr, "\r\n"); 183116111Sphk} 184116111Sphk