buffer.c revision 204917
1204917Sdes/* $OpenBSD: buffer.c,v 1.32 2010/02/09 03:56:28 djm Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 657429Smarkm * Functions for manipulating fifo buffers (that can grow if needed). 760573Skris * 865668Skris * As far as I am concerned, the code I have written for this software 965668Skris * can be used freely for any purpose. Any derived versions of this 1065668Skris * software must be clearly marked as such, and if the derived work is 1165668Skris * incompatible with the protocol description in the RFC file, it must be 1265668Skris * called by a name other than "ssh" or "Secure Shell". 1357429Smarkm */ 1457429Smarkm 1557429Smarkm#include "includes.h" 1657429Smarkm 17162852Sdes#include <sys/param.h> 18162852Sdes 19162852Sdes#include <stdio.h> 20162852Sdes#include <string.h> 21162852Sdes#include <stdarg.h> 22162852Sdes 2357429Smarkm#include "xmalloc.h" 2457429Smarkm#include "buffer.h" 2576259Sgreen#include "log.h" 2657429Smarkm 27162852Sdes#define BUFFER_MAX_CHUNK 0x100000 28162852Sdes#define BUFFER_MAX_LEN 0xa00000 29162852Sdes#define BUFFER_ALLOCSZ 0x008000 30162852Sdes 3157429Smarkm/* Initializes the buffer structure. */ 3257429Smarkm 3360573Skrisvoid 3457429Smarkmbuffer_init(Buffer *buffer) 3557429Smarkm{ 36120489Sjoe const u_int len = 4096; 37120489Sjoe 38120489Sjoe buffer->alloc = 0; 39120489Sjoe buffer->buf = xmalloc(len); 40120489Sjoe buffer->alloc = len; 4157429Smarkm buffer->offset = 0; 4257429Smarkm buffer->end = 0; 4357429Smarkm} 4457429Smarkm 4557429Smarkm/* Frees any memory used for the buffer. */ 4657429Smarkm 4760573Skrisvoid 4857429Smarkmbuffer_free(Buffer *buffer) 4957429Smarkm{ 50120489Sjoe if (buffer->alloc > 0) { 51120489Sjoe memset(buffer->buf, 0, buffer->alloc); 52124208Sdes buffer->alloc = 0; 53120489Sjoe xfree(buffer->buf); 54120489Sjoe } 5557429Smarkm} 5657429Smarkm 5757429Smarkm/* 5857429Smarkm * Clears any data from the buffer, making it empty. This does not actually 5957429Smarkm * zero the memory. 6057429Smarkm */ 6157429Smarkm 6260573Skrisvoid 6357429Smarkmbuffer_clear(Buffer *buffer) 6457429Smarkm{ 6557429Smarkm buffer->offset = 0; 6657429Smarkm buffer->end = 0; 6757429Smarkm} 6857429Smarkm 6957429Smarkm/* Appends data to the buffer, expanding it if necessary. */ 7057429Smarkm 7160573Skrisvoid 7292555Sdesbuffer_append(Buffer *buffer, const void *data, u_int len) 7357429Smarkm{ 7492555Sdes void *p; 7592555Sdes p = buffer_append_space(buffer, len); 7692555Sdes memcpy(p, data, len); 7757429Smarkm} 7857429Smarkm 79162852Sdesstatic int 80162852Sdesbuffer_compact(Buffer *buffer) 81162852Sdes{ 82162852Sdes /* 83162852Sdes * If the buffer is quite empty, but all data is at the end, move the 84162852Sdes * data to the beginning. 85162852Sdes */ 86162852Sdes if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) { 87162852Sdes memmove(buffer->buf, buffer->buf + buffer->offset, 88162852Sdes buffer->end - buffer->offset); 89162852Sdes buffer->end -= buffer->offset; 90162852Sdes buffer->offset = 0; 91162852Sdes return (1); 92162852Sdes } 93162852Sdes return (0); 94162852Sdes} 95162852Sdes 9657429Smarkm/* 9757429Smarkm * Appends space to the buffer, expanding the buffer if necessary. This does 9857429Smarkm * not actually copy the data into the buffer, but instead returns a pointer 9957429Smarkm * to the allocated region. 10057429Smarkm */ 10157429Smarkm 10292555Sdesvoid * 10392555Sdesbuffer_append_space(Buffer *buffer, u_int len) 10457429Smarkm{ 105120113Snectar u_int newlen; 10692555Sdes void *p; 10792555Sdes 108147001Sdes if (len > BUFFER_MAX_CHUNK) 10999060Sdes fatal("buffer_append_space: len %u not supported", len); 11099060Sdes 11157429Smarkm /* If the buffer is empty, start using it from the beginning. */ 11257429Smarkm if (buffer->offset == buffer->end) { 11357429Smarkm buffer->offset = 0; 11457429Smarkm buffer->end = 0; 11557429Smarkm } 11657429Smarkmrestart: 11757429Smarkm /* If there is enough space to store all data, store it now. */ 11857429Smarkm if (buffer->end + len < buffer->alloc) { 11992555Sdes p = buffer->buf + buffer->end; 12057429Smarkm buffer->end += len; 12192555Sdes return p; 12257429Smarkm } 123162852Sdes 124162852Sdes /* Compact data back to the start of the buffer if necessary */ 125162852Sdes if (buffer_compact(buffer)) 12657429Smarkm goto restart; 127162852Sdes 12857429Smarkm /* Increase the size of the buffer and retry. */ 129162852Sdes newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ); 130147001Sdes if (newlen > BUFFER_MAX_LEN) 13199060Sdes fatal("buffer_append_space: alloc %u not supported", 132120113Snectar newlen); 133162852Sdes buffer->buf = xrealloc(buffer->buf, 1, newlen); 134120113Snectar buffer->alloc = newlen; 13557429Smarkm goto restart; 13692555Sdes /* NOTREACHED */ 13757429Smarkm} 13857429Smarkm 139162852Sdes/* 140162852Sdes * Check whether an allocation of 'len' will fit in the buffer 141162852Sdes * This must follow the same math as buffer_append_space 142162852Sdes */ 143162852Sdesint 144162852Sdesbuffer_check_alloc(Buffer *buffer, u_int len) 145162852Sdes{ 146162852Sdes if (buffer->offset == buffer->end) { 147162852Sdes buffer->offset = 0; 148162852Sdes buffer->end = 0; 149162852Sdes } 150162852Sdes restart: 151162852Sdes if (buffer->end + len < buffer->alloc) 152162852Sdes return (1); 153162852Sdes if (buffer_compact(buffer)) 154162852Sdes goto restart; 155162852Sdes if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN) 156162852Sdes return (1); 157162852Sdes return (0); 158162852Sdes} 159162852Sdes 16057429Smarkm/* Returns the number of bytes of data in the buffer. */ 16157429Smarkm 16276259Sgreenu_int 163204917Sdesbuffer_len(const Buffer *buffer) 16457429Smarkm{ 16557429Smarkm return buffer->end - buffer->offset; 16657429Smarkm} 16757429Smarkm 16857429Smarkm/* Gets data from the beginning of the buffer. */ 16957429Smarkm 170146998Sdesint 171146998Sdesbuffer_get_ret(Buffer *buffer, void *buf, u_int len) 17257429Smarkm{ 173146998Sdes if (len > buffer->end - buffer->offset) { 174146998Sdes error("buffer_get_ret: trying to get more bytes %d than in buffer %d", 17576259Sgreen len, buffer->end - buffer->offset); 176146998Sdes return (-1); 177146998Sdes } 17857429Smarkm memcpy(buf, buffer->buf + buffer->offset, len); 17957429Smarkm buffer->offset += len; 180146998Sdes return (0); 18157429Smarkm} 18257429Smarkm 183146998Sdesvoid 184146998Sdesbuffer_get(Buffer *buffer, void *buf, u_int len) 185146998Sdes{ 186146998Sdes if (buffer_get_ret(buffer, buf, len) == -1) 187146998Sdes fatal("buffer_get: buffer error"); 188146998Sdes} 189146998Sdes 19057429Smarkm/* Consumes the given number of bytes from the beginning of the buffer. */ 19157429Smarkm 192146998Sdesint 193146998Sdesbuffer_consume_ret(Buffer *buffer, u_int bytes) 194146998Sdes{ 195146998Sdes if (bytes > buffer->end - buffer->offset) { 196146998Sdes error("buffer_consume_ret: trying to get more bytes than in buffer"); 197146998Sdes return (-1); 198146998Sdes } 199146998Sdes buffer->offset += bytes; 200146998Sdes return (0); 201146998Sdes} 202146998Sdes 20360573Skrisvoid 20476259Sgreenbuffer_consume(Buffer *buffer, u_int bytes) 20557429Smarkm{ 206146998Sdes if (buffer_consume_ret(buffer, bytes) == -1) 207146998Sdes fatal("buffer_consume: buffer error"); 20857429Smarkm} 20957429Smarkm 21057429Smarkm/* Consumes the given number of bytes from the end of the buffer. */ 21157429Smarkm 212146998Sdesint 213146998Sdesbuffer_consume_end_ret(Buffer *buffer, u_int bytes) 214146998Sdes{ 215146998Sdes if (bytes > buffer->end - buffer->offset) 216146998Sdes return (-1); 217146998Sdes buffer->end -= bytes; 218146998Sdes return (0); 219146998Sdes} 220146998Sdes 22160573Skrisvoid 22276259Sgreenbuffer_consume_end(Buffer *buffer, u_int bytes) 22357429Smarkm{ 224146998Sdes if (buffer_consume_end_ret(buffer, bytes) == -1) 22560573Skris fatal("buffer_consume_end: trying to get more bytes than in buffer"); 22657429Smarkm} 22757429Smarkm 22857429Smarkm/* Returns a pointer to the first used byte in the buffer. */ 22957429Smarkm 23092555Sdesvoid * 231204917Sdesbuffer_ptr(const Buffer *buffer) 23257429Smarkm{ 23357429Smarkm return buffer->buf + buffer->offset; 23457429Smarkm} 23557429Smarkm 23657429Smarkm/* Dumps the contents of the buffer to stderr. */ 23757429Smarkm 23860573Skrisvoid 239204917Sdesbuffer_dump(const Buffer *buffer) 24057429Smarkm{ 241126274Sdes u_int i; 24292555Sdes u_char *ucp = buffer->buf; 24357429Smarkm 24476259Sgreen for (i = buffer->offset; i < buffer->end; i++) { 24576259Sgreen fprintf(stderr, "%02x", ucp[i]); 24676259Sgreen if ((i-buffer->offset)%16==15) 24776259Sgreen fprintf(stderr, "\r\n"); 24876259Sgreen else if ((i-buffer->offset)%2==1) 24976259Sgreen fprintf(stderr, " "); 25076259Sgreen } 25176259Sgreen fprintf(stderr, "\r\n"); 25257429Smarkm} 253