1255767Sdes/* $OpenBSD: buffer.c,v 1.33 2013/05/17 00:13:13 djm Exp $ */ 2224638Sbrooks/* $FreeBSD$ */ 357429Smarkm/* 457429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 557429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 657429Smarkm * All rights reserved 757429Smarkm * Functions for manipulating fifo buffers (that can grow if needed). 860573Skris * 965668Skris * As far as I am concerned, the code I have written for this software 1065668Skris * can be used freely for any purpose. Any derived versions of this 1165668Skris * software must be clearly marked as such, and if the derived work is 1265668Skris * incompatible with the protocol description in the RFC file, it must be 1365668Skris * called by a name other than "ssh" or "Secure Shell". 1457429Smarkm */ 1557429Smarkm 1657429Smarkm#include "includes.h" 1757429Smarkm 18162852Sdes#include <sys/param.h> 19162852Sdes 20162852Sdes#include <stdio.h> 21162852Sdes#include <string.h> 22162852Sdes#include <stdarg.h> 23162852Sdes 2457429Smarkm#include "xmalloc.h" 2557429Smarkm#include "buffer.h" 2676259Sgreen#include "log.h" 2757429Smarkm 28162852Sdes#define BUFFER_MAX_CHUNK 0x100000 29224638Sbrooks#define BUFFER_MAX_LEN 0x4000000 /* 64MB */ 30162852Sdes#define BUFFER_ALLOCSZ 0x008000 31162852Sdes 3257429Smarkm/* Initializes the buffer structure. */ 3357429Smarkm 3460573Skrisvoid 3557429Smarkmbuffer_init(Buffer *buffer) 3657429Smarkm{ 37120489Sjoe const u_int len = 4096; 38120489Sjoe 39120489Sjoe buffer->alloc = 0; 40120489Sjoe buffer->buf = xmalloc(len); 41120489Sjoe buffer->alloc = len; 4257429Smarkm buffer->offset = 0; 4357429Smarkm buffer->end = 0; 4457429Smarkm} 4557429Smarkm 4657429Smarkm/* Frees any memory used for the buffer. */ 4757429Smarkm 4860573Skrisvoid 4957429Smarkmbuffer_free(Buffer *buffer) 5057429Smarkm{ 51120489Sjoe if (buffer->alloc > 0) { 52120489Sjoe memset(buffer->buf, 0, buffer->alloc); 53124208Sdes buffer->alloc = 0; 54255767Sdes free(buffer->buf); 55120489Sjoe } 5657429Smarkm} 5757429Smarkm 5857429Smarkm/* 5957429Smarkm * Clears any data from the buffer, making it empty. This does not actually 6057429Smarkm * zero the memory. 6157429Smarkm */ 6257429Smarkm 6360573Skrisvoid 6457429Smarkmbuffer_clear(Buffer *buffer) 6557429Smarkm{ 6657429Smarkm buffer->offset = 0; 6757429Smarkm buffer->end = 0; 6857429Smarkm} 6957429Smarkm 7057429Smarkm/* Appends data to the buffer, expanding it if necessary. */ 7157429Smarkm 7260573Skrisvoid 7392555Sdesbuffer_append(Buffer *buffer, const void *data, u_int len) 7457429Smarkm{ 7592555Sdes void *p; 7692555Sdes p = buffer_append_space(buffer, len); 7792555Sdes memcpy(p, data, len); 7857429Smarkm} 7957429Smarkm 80162852Sdesstatic int 81162852Sdesbuffer_compact(Buffer *buffer) 82162852Sdes{ 83162852Sdes /* 84162852Sdes * If the buffer is quite empty, but all data is at the end, move the 85162852Sdes * data to the beginning. 86162852Sdes */ 87162852Sdes if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) { 88162852Sdes memmove(buffer->buf, buffer->buf + buffer->offset, 89162852Sdes buffer->end - buffer->offset); 90162852Sdes buffer->end -= buffer->offset; 91162852Sdes buffer->offset = 0; 92162852Sdes return (1); 93162852Sdes } 94162852Sdes return (0); 95162852Sdes} 96162852Sdes 9757429Smarkm/* 9857429Smarkm * Appends space to the buffer, expanding the buffer if necessary. This does 9957429Smarkm * not actually copy the data into the buffer, but instead returns a pointer 10057429Smarkm * to the allocated region. 10157429Smarkm */ 10257429Smarkm 10392555Sdesvoid * 10492555Sdesbuffer_append_space(Buffer *buffer, u_int len) 10557429Smarkm{ 106120113Snectar u_int newlen; 10792555Sdes void *p; 10892555Sdes 109147001Sdes if (len > BUFFER_MAX_CHUNK) 11099060Sdes fatal("buffer_append_space: len %u not supported", len); 11199060Sdes 11257429Smarkm /* If the buffer is empty, start using it from the beginning. */ 11357429Smarkm if (buffer->offset == buffer->end) { 11457429Smarkm buffer->offset = 0; 11557429Smarkm buffer->end = 0; 11657429Smarkm } 11757429Smarkmrestart: 11857429Smarkm /* If there is enough space to store all data, store it now. */ 11957429Smarkm if (buffer->end + len < buffer->alloc) { 12092555Sdes p = buffer->buf + buffer->end; 12157429Smarkm buffer->end += len; 12292555Sdes return p; 12357429Smarkm } 124162852Sdes 125162852Sdes /* Compact data back to the start of the buffer if necessary */ 126162852Sdes if (buffer_compact(buffer)) 12757429Smarkm goto restart; 128162852Sdes 12957429Smarkm /* Increase the size of the buffer and retry. */ 130162852Sdes newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ); 131147001Sdes if (newlen > BUFFER_MAX_LEN) 13299060Sdes fatal("buffer_append_space: alloc %u not supported", 133120113Snectar newlen); 134162852Sdes buffer->buf = xrealloc(buffer->buf, 1, newlen); 135120113Snectar buffer->alloc = newlen; 13657429Smarkm goto restart; 13792555Sdes /* NOTREACHED */ 13857429Smarkm} 13957429Smarkm 140162852Sdes/* 141162852Sdes * Check whether an allocation of 'len' will fit in the buffer 142162852Sdes * This must follow the same math as buffer_append_space 143162852Sdes */ 144162852Sdesint 145162852Sdesbuffer_check_alloc(Buffer *buffer, u_int len) 146162852Sdes{ 147162852Sdes if (buffer->offset == buffer->end) { 148162852Sdes buffer->offset = 0; 149162852Sdes buffer->end = 0; 150162852Sdes } 151162852Sdes restart: 152162852Sdes if (buffer->end + len < buffer->alloc) 153162852Sdes return (1); 154162852Sdes if (buffer_compact(buffer)) 155162852Sdes goto restart; 156162852Sdes if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN) 157162852Sdes return (1); 158162852Sdes return (0); 159162852Sdes} 160162852Sdes 16157429Smarkm/* Returns the number of bytes of data in the buffer. */ 16257429Smarkm 16376259Sgreenu_int 164204917Sdesbuffer_len(const Buffer *buffer) 16557429Smarkm{ 16657429Smarkm return buffer->end - buffer->offset; 16757429Smarkm} 16857429Smarkm 169224638Sbrooks/* Returns the maximum number of bytes of data that may be in the buffer. */ 170224638Sbrooksu_int 171224638Sbrooksbuffer_get_max_len(void) 172224638Sbrooks{ 173224638Sbrooks return (BUFFER_MAX_LEN); 174224638Sbrooks} 175224638Sbrooks 17657429Smarkm/* Gets data from the beginning of the buffer. */ 17757429Smarkm 178146998Sdesint 179146998Sdesbuffer_get_ret(Buffer *buffer, void *buf, u_int len) 18057429Smarkm{ 181146998Sdes if (len > buffer->end - buffer->offset) { 182146998Sdes error("buffer_get_ret: trying to get more bytes %d than in buffer %d", 18376259Sgreen len, buffer->end - buffer->offset); 184146998Sdes return (-1); 185146998Sdes } 18657429Smarkm memcpy(buf, buffer->buf + buffer->offset, len); 18757429Smarkm buffer->offset += len; 188146998Sdes return (0); 18957429Smarkm} 19057429Smarkm 191146998Sdesvoid 192146998Sdesbuffer_get(Buffer *buffer, void *buf, u_int len) 193146998Sdes{ 194146998Sdes if (buffer_get_ret(buffer, buf, len) == -1) 195146998Sdes fatal("buffer_get: buffer error"); 196146998Sdes} 197146998Sdes 19857429Smarkm/* Consumes the given number of bytes from the beginning of the buffer. */ 19957429Smarkm 200146998Sdesint 201146998Sdesbuffer_consume_ret(Buffer *buffer, u_int bytes) 202146998Sdes{ 203146998Sdes if (bytes > buffer->end - buffer->offset) { 204146998Sdes error("buffer_consume_ret: trying to get more bytes than in buffer"); 205146998Sdes return (-1); 206146998Sdes } 207146998Sdes buffer->offset += bytes; 208146998Sdes return (0); 209146998Sdes} 210146998Sdes 21160573Skrisvoid 21276259Sgreenbuffer_consume(Buffer *buffer, u_int bytes) 21357429Smarkm{ 214146998Sdes if (buffer_consume_ret(buffer, bytes) == -1) 215146998Sdes fatal("buffer_consume: buffer error"); 21657429Smarkm} 21757429Smarkm 21857429Smarkm/* Consumes the given number of bytes from the end of the buffer. */ 21957429Smarkm 220146998Sdesint 221146998Sdesbuffer_consume_end_ret(Buffer *buffer, u_int bytes) 222146998Sdes{ 223146998Sdes if (bytes > buffer->end - buffer->offset) 224146998Sdes return (-1); 225146998Sdes buffer->end -= bytes; 226146998Sdes return (0); 227146998Sdes} 228146998Sdes 22960573Skrisvoid 23076259Sgreenbuffer_consume_end(Buffer *buffer, u_int bytes) 23157429Smarkm{ 232146998Sdes if (buffer_consume_end_ret(buffer, bytes) == -1) 23360573Skris fatal("buffer_consume_end: trying to get more bytes than in buffer"); 23457429Smarkm} 23557429Smarkm 23657429Smarkm/* Returns a pointer to the first used byte in the buffer. */ 23757429Smarkm 23892555Sdesvoid * 239204917Sdesbuffer_ptr(const Buffer *buffer) 24057429Smarkm{ 24157429Smarkm return buffer->buf + buffer->offset; 24257429Smarkm} 24357429Smarkm 24457429Smarkm/* Dumps the contents of the buffer to stderr. */ 24557429Smarkm 24660573Skrisvoid 247204917Sdesbuffer_dump(const Buffer *buffer) 24857429Smarkm{ 249126274Sdes u_int i; 25092555Sdes u_char *ucp = buffer->buf; 25157429Smarkm 25276259Sgreen for (i = buffer->offset; i < buffer->end; i++) { 25376259Sgreen fprintf(stderr, "%02x", ucp[i]); 25476259Sgreen if ((i-buffer->offset)%16==15) 25576259Sgreen fprintf(stderr, "\r\n"); 25676259Sgreen else if ((i-buffer->offset)%2==1) 25776259Sgreen fprintf(stderr, " "); 25876259Sgreen } 25976259Sgreen fprintf(stderr, "\r\n"); 26057429Smarkm} 261