1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Author: Tatu Ylonen <ylo@cs.hut.fi> 3*0Sstevel@tonic-gate * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4*0Sstevel@tonic-gate * All rights reserved 5*0Sstevel@tonic-gate * Functions for manipulating fifo buffers (that can grow if needed). 6*0Sstevel@tonic-gate * 7*0Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software 8*0Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this 9*0Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is 10*0Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be 11*0Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell". 12*0Sstevel@tonic-gate */ 13*0Sstevel@tonic-gate 14*0Sstevel@tonic-gate #include "includes.h" 15*0Sstevel@tonic-gate RCSID("$OpenBSD: buffer.c,v 1.16 2002/06/26 08:54:18 markus Exp $"); 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 18*0Sstevel@tonic-gate 19*0Sstevel@tonic-gate #include "xmalloc.h" 20*0Sstevel@tonic-gate #include "buffer.h" 21*0Sstevel@tonic-gate #include "log.h" 22*0Sstevel@tonic-gate 23*0Sstevel@tonic-gate /* Initializes the buffer structure. */ 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate void 26*0Sstevel@tonic-gate buffer_init(Buffer *buffer) 27*0Sstevel@tonic-gate { 28*0Sstevel@tonic-gate const u_int len = 4096; 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate buffer->alloc = 0; 31*0Sstevel@tonic-gate buffer->buf = xmalloc(len); 32*0Sstevel@tonic-gate buffer->alloc = len; 33*0Sstevel@tonic-gate buffer->offset = 0; 34*0Sstevel@tonic-gate buffer->end = 0; 35*0Sstevel@tonic-gate } 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate /* Frees any memory used for the buffer. */ 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate void 40*0Sstevel@tonic-gate buffer_free(Buffer *buffer) 41*0Sstevel@tonic-gate { 42*0Sstevel@tonic-gate if (buffer->alloc > 0) { 43*0Sstevel@tonic-gate memset(buffer->buf, 0, buffer->alloc); 44*0Sstevel@tonic-gate xfree(buffer->buf); 45*0Sstevel@tonic-gate } 46*0Sstevel@tonic-gate } 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate /* 49*0Sstevel@tonic-gate * Clears any data from the buffer, making it empty. This does not actually 50*0Sstevel@tonic-gate * zero the memory. 51*0Sstevel@tonic-gate */ 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate void 54*0Sstevel@tonic-gate buffer_clear(Buffer *buffer) 55*0Sstevel@tonic-gate { 56*0Sstevel@tonic-gate buffer->offset = 0; 57*0Sstevel@tonic-gate buffer->end = 0; 58*0Sstevel@tonic-gate } 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate /* Appends data to the buffer, expanding it if necessary. */ 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate void 63*0Sstevel@tonic-gate buffer_append(Buffer *buffer, const void *data, u_int len) 64*0Sstevel@tonic-gate { 65*0Sstevel@tonic-gate void *p; 66*0Sstevel@tonic-gate p = buffer_append_space(buffer, len); 67*0Sstevel@tonic-gate memcpy(p, data, len); 68*0Sstevel@tonic-gate } 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate /* 71*0Sstevel@tonic-gate * Appends space to the buffer, expanding the buffer if necessary. This does 72*0Sstevel@tonic-gate * not actually copy the data into the buffer, but instead returns a pointer 73*0Sstevel@tonic-gate * to the allocated region. 74*0Sstevel@tonic-gate */ 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate void * 77*0Sstevel@tonic-gate buffer_append_space(Buffer *buffer, u_int len) 78*0Sstevel@tonic-gate { 79*0Sstevel@tonic-gate u_int newlen; 80*0Sstevel@tonic-gate void *p; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate if (len > 0x100000) 83*0Sstevel@tonic-gate fatal("buffer_append_space: len %u not supported", len); 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate /* If the buffer is empty, start using it from the beginning. */ 86*0Sstevel@tonic-gate if (buffer->offset == buffer->end) { 87*0Sstevel@tonic-gate buffer->offset = 0; 88*0Sstevel@tonic-gate buffer->end = 0; 89*0Sstevel@tonic-gate } 90*0Sstevel@tonic-gate restart: 91*0Sstevel@tonic-gate /* If there is enough space to store all data, store it now. */ 92*0Sstevel@tonic-gate if (buffer->end + len < buffer->alloc) { 93*0Sstevel@tonic-gate p = buffer->buf + buffer->end; 94*0Sstevel@tonic-gate buffer->end += len; 95*0Sstevel@tonic-gate return p; 96*0Sstevel@tonic-gate } 97*0Sstevel@tonic-gate /* 98*0Sstevel@tonic-gate * If the buffer is quite empty, but all data is at the end, move the 99*0Sstevel@tonic-gate * data to the beginning and retry. 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate if (buffer->offset > buffer->alloc / 2) { 102*0Sstevel@tonic-gate memmove(buffer->buf, buffer->buf + buffer->offset, 103*0Sstevel@tonic-gate buffer->end - buffer->offset); 104*0Sstevel@tonic-gate buffer->end -= buffer->offset; 105*0Sstevel@tonic-gate buffer->offset = 0; 106*0Sstevel@tonic-gate goto restart; 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate /* Increase the size of the buffer and retry. */ 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate newlen = buffer->alloc + len + 32768; 111*0Sstevel@tonic-gate if (newlen > 0xa00000) 112*0Sstevel@tonic-gate fatal("buffer_append_space: alloc %u not supported", 113*0Sstevel@tonic-gate newlen); 114*0Sstevel@tonic-gate buffer->buf = xrealloc(buffer->buf, newlen); 115*0Sstevel@tonic-gate buffer->alloc = newlen; 116*0Sstevel@tonic-gate goto restart; 117*0Sstevel@tonic-gate /* NOTREACHED */ 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate /* Returns the number of bytes of data in the buffer. */ 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate u_int 123*0Sstevel@tonic-gate buffer_len(Buffer *buffer) 124*0Sstevel@tonic-gate { 125*0Sstevel@tonic-gate return buffer->end - buffer->offset; 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* Gets data from the beginning of the buffer. */ 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate void 131*0Sstevel@tonic-gate buffer_get(Buffer *buffer, void *buf, u_int len) 132*0Sstevel@tonic-gate { 133*0Sstevel@tonic-gate if (len > buffer->end - buffer->offset) 134*0Sstevel@tonic-gate fatal("buffer_get: trying to get more bytes %d than in buffer %d", 135*0Sstevel@tonic-gate len, buffer->end - buffer->offset); 136*0Sstevel@tonic-gate memcpy(buf, buffer->buf + buffer->offset, len); 137*0Sstevel@tonic-gate buffer->offset += len; 138*0Sstevel@tonic-gate } 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate /* Consumes the given number of bytes from the beginning of the buffer. */ 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate void 143*0Sstevel@tonic-gate buffer_consume(Buffer *buffer, u_int bytes) 144*0Sstevel@tonic-gate { 145*0Sstevel@tonic-gate if (bytes > buffer->end - buffer->offset) 146*0Sstevel@tonic-gate fatal("buffer_consume: trying to get more bytes than in buffer"); 147*0Sstevel@tonic-gate buffer->offset += bytes; 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate /* Consumes the given number of bytes from the end of the buffer. */ 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate void 153*0Sstevel@tonic-gate buffer_consume_end(Buffer *buffer, u_int bytes) 154*0Sstevel@tonic-gate { 155*0Sstevel@tonic-gate if (bytes > buffer->end - buffer->offset) 156*0Sstevel@tonic-gate fatal("buffer_consume_end: trying to get more bytes than in buffer"); 157*0Sstevel@tonic-gate buffer->end -= bytes; 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate /* Returns a pointer to the first used byte in the buffer. */ 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate void * 163*0Sstevel@tonic-gate buffer_ptr(Buffer *buffer) 164*0Sstevel@tonic-gate { 165*0Sstevel@tonic-gate return buffer->buf + buffer->offset; 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate /* Dumps the contents of the buffer to stderr. */ 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate void 171*0Sstevel@tonic-gate buffer_dump(Buffer *buffer) 172*0Sstevel@tonic-gate { 173*0Sstevel@tonic-gate int i; 174*0Sstevel@tonic-gate u_char *ucp = buffer->buf; 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate for (i = buffer->offset; i < buffer->end; i++) { 177*0Sstevel@tonic-gate fprintf(stderr, "%02x", ucp[i]); 178*0Sstevel@tonic-gate if ((i-buffer->offset)%16==15) 179*0Sstevel@tonic-gate fprintf(stderr, "\r\n"); 180*0Sstevel@tonic-gate else if ((i-buffer->offset)%2==1) 181*0Sstevel@tonic-gate fprintf(stderr, " "); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate fprintf(stderr, "\r\n"); 184*0Sstevel@tonic-gate } 185