bf_lbuf.c revision 100928
168651Skris/* crypto/bio/bf_buff.c */ 268651Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 368651Skris * All rights reserved. 468651Skris * 568651Skris * This package is an SSL implementation written 668651Skris * by Eric Young (eay@cryptsoft.com). 768651Skris * The implementation was written so as to conform with Netscapes SSL. 868651Skris * 968651Skris * This library is free for commercial and non-commercial use as long as 1068651Skris * the following conditions are aheared to. The following conditions 1168651Skris * apply to all code found in this distribution, be it the RC4, RSA, 1268651Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1368651Skris * included with this distribution is covered by the same copyright terms 1468651Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 1568651Skris * 1668651Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1768651Skris * the code are not to be removed. 1868651Skris * If this package is used in a product, Eric Young should be given attribution 1968651Skris * as the author of the parts of the library used. 2068651Skris * This can be in the form of a textual message at program startup or 2168651Skris * in documentation (online or textual) provided with the package. 2268651Skris * 2368651Skris * Redistribution and use in source and binary forms, with or without 2468651Skris * modification, are permitted provided that the following conditions 2568651Skris * are met: 2668651Skris * 1. Redistributions of source code must retain the copyright 2768651Skris * notice, this list of conditions and the following disclaimer. 2868651Skris * 2. Redistributions in binary form must reproduce the above copyright 2968651Skris * notice, this list of conditions and the following disclaimer in the 3068651Skris * documentation and/or other materials provided with the distribution. 3168651Skris * 3. All advertising materials mentioning features or use of this software 3268651Skris * must display the following acknowledgement: 3368651Skris * "This product includes cryptographic software written by 3468651Skris * Eric Young (eay@cryptsoft.com)" 3568651Skris * The word 'cryptographic' can be left out if the rouines from the library 3668651Skris * being used are not cryptographic related :-). 3768651Skris * 4. If you include any Windows specific code (or a derivative thereof) from 3868651Skris * the apps directory (application code) you must include an acknowledgement: 3968651Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 4068651Skris * 4168651Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4268651Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4368651Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4468651Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4568651Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4668651Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4768651Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4868651Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4968651Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5068651Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5168651Skris * SUCH DAMAGE. 5268651Skris * 5368651Skris * The licence and distribution terms for any publically available version or 5468651Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5568651Skris * copied and put under another distribution licence 5668651Skris * [including the GNU Public Licence.] 5768651Skris */ 5868651Skris 5968651Skris#include <stdio.h> 6068651Skris#include <errno.h> 6168651Skris#include "cryptlib.h" 6268651Skris#include <openssl/bio.h> 6368651Skris#include <openssl/evp.h> 6468651Skris 6568651Skrisstatic int linebuffer_write(BIO *h, const char *buf,int num); 6668651Skrisstatic int linebuffer_read(BIO *h, char *buf, int size); 6768651Skrisstatic int linebuffer_puts(BIO *h, const char *str); 6868651Skrisstatic int linebuffer_gets(BIO *h, char *str, int size); 6968651Skrisstatic long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 7068651Skrisstatic int linebuffer_new(BIO *h); 7168651Skrisstatic int linebuffer_free(BIO *data); 7268651Skrisstatic long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 7368651Skris 7468651Skris/* A 10k maximum should be enough for most purposes */ 7568651Skris#define DEFAULT_LINEBUFFER_SIZE 1024*10 7668651Skris 7768651Skris/* #define DEBUG */ 7868651Skris 7968651Skrisstatic BIO_METHOD methods_linebuffer= 8068651Skris { 8168651Skris BIO_TYPE_LINEBUFFER, 8268651Skris "linebuffer", 8368651Skris linebuffer_write, 8468651Skris linebuffer_read, 8568651Skris linebuffer_puts, 8668651Skris linebuffer_gets, 8768651Skris linebuffer_ctrl, 8868651Skris linebuffer_new, 8968651Skris linebuffer_free, 9068651Skris linebuffer_callback_ctrl, 9168651Skris }; 9268651Skris 9368651SkrisBIO_METHOD *BIO_f_linebuffer(void) 9468651Skris { 9568651Skris return(&methods_linebuffer); 9668651Skris } 9768651Skris 9868651Skristypedef struct bio_linebuffer_ctx_struct 9968651Skris { 10068651Skris char *obuf; /* the output char array */ 10168651Skris int obuf_size; /* how big is the output buffer */ 10268651Skris int obuf_len; /* how many bytes are in it */ 10368651Skris } BIO_LINEBUFFER_CTX; 10468651Skris 10568651Skrisstatic int linebuffer_new(BIO *bi) 10668651Skris { 10768651Skris BIO_LINEBUFFER_CTX *ctx; 10868651Skris 10968651Skris ctx=(BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX)); 11068651Skris if (ctx == NULL) return(0); 11168651Skris ctx->obuf=(char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 11268651Skris if (ctx->obuf == NULL) { OPENSSL_free(ctx); return(0); } 11368651Skris ctx->obuf_size=DEFAULT_LINEBUFFER_SIZE; 11468651Skris ctx->obuf_len=0; 11568651Skris 11668651Skris bi->init=1; 11768651Skris bi->ptr=(char *)ctx; 11868651Skris bi->flags=0; 11968651Skris return(1); 12068651Skris } 12168651Skris 12268651Skrisstatic int linebuffer_free(BIO *a) 12368651Skris { 12468651Skris BIO_LINEBUFFER_CTX *b; 12568651Skris 12668651Skris if (a == NULL) return(0); 12768651Skris b=(BIO_LINEBUFFER_CTX *)a->ptr; 12868651Skris if (b->obuf != NULL) OPENSSL_free(b->obuf); 12968651Skris OPENSSL_free(a->ptr); 13068651Skris a->ptr=NULL; 13168651Skris a->init=0; 13268651Skris a->flags=0; 13368651Skris return(1); 13468651Skris } 13568651Skris 13668651Skrisstatic int linebuffer_read(BIO *b, char *out, int outl) 13768651Skris { 13868651Skris int ret=0; 13968651Skris 14068651Skris if (out == NULL) return(0); 14168651Skris if (b->next_bio == NULL) return(0); 14268651Skris ret=BIO_read(b->next_bio,out,outl); 14368651Skris BIO_clear_retry_flags(b); 14468651Skris BIO_copy_next_retry(b); 14568651Skris return(ret); 14668651Skris } 14768651Skris 14868651Skrisstatic int linebuffer_write(BIO *b, const char *in, int inl) 14968651Skris { 15068651Skris int i,num=0,foundnl; 15168651Skris BIO_LINEBUFFER_CTX *ctx; 15268651Skris 15368651Skris if ((in == NULL) || (inl <= 0)) return(0); 15468651Skris ctx=(BIO_LINEBUFFER_CTX *)b->ptr; 15568651Skris if ((ctx == NULL) || (b->next_bio == NULL)) return(0); 15668651Skris 15768651Skris BIO_clear_retry_flags(b); 15868651Skris 15968651Skris do 16068651Skris { 16168651Skris const char *p; 16268651Skris 16368651Skris for(p = in; p < in + inl && *p != '\n'; p++) 16468651Skris ; 16568651Skris if (*p == '\n') 16668651Skris { 16768651Skris p++; 16868651Skris foundnl = 1; 16968651Skris } 17068651Skris else 17168651Skris foundnl = 0; 17268651Skris 17368651Skris /* If a NL was found and we already have text in the save 17468651Skris buffer, concatenate them and write */ 17568651Skris while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 17668651Skris && ctx->obuf_len > 0) 17768651Skris { 17868651Skris int orig_olen = ctx->obuf_len; 17968651Skris 18068651Skris i = ctx->obuf_size - ctx->obuf_len; 18168651Skris if (p - in > 0) 18268651Skris { 18368651Skris if (i >= p - in) 18468651Skris { 18568651Skris memcpy(&(ctx->obuf[ctx->obuf_len]), 18668651Skris in,p - in); 18768651Skris ctx->obuf_len += p - in; 18868651Skris inl -= p - in; 18968651Skris num += p - in; 19068651Skris in = p; 19168651Skris } 19268651Skris else 19368651Skris { 19468651Skris memcpy(&(ctx->obuf[ctx->obuf_len]), 19568651Skris in,i); 19668651Skris ctx->obuf_len += i; 19768651Skris inl -= i; 19868651Skris in += i; 19968651Skris num += i; 20068651Skris } 20168651Skris } 20268651Skris 203100928Snectar#if 0 20468651SkrisBIO_write(b->next_bio, "<*<", 3); 20568651Skris#endif 20668651Skris i=BIO_write(b->next_bio, 20768651Skris ctx->obuf, ctx->obuf_len); 20868651Skris if (i <= 0) 20968651Skris { 21068651Skris ctx->obuf_len = orig_olen; 21168651Skris BIO_copy_next_retry(b); 21268651Skris 213100928Snectar#if 0 21468651SkrisBIO_write(b->next_bio, ">*>", 3); 21568651Skris#endif 21668651Skris if (i < 0) return((num > 0)?num:i); 21768651Skris if (i == 0) return(num); 21868651Skris } 219100928Snectar#if 0 22068651SkrisBIO_write(b->next_bio, ">*>", 3); 22168651Skris#endif 22268651Skris if (i < ctx->obuf_len) 22368651Skris memmove(ctx->obuf, ctx->obuf + i, 22468651Skris ctx->obuf_len - i); 22568651Skris ctx->obuf_len-=i; 22668651Skris } 22768651Skris 22868651Skris /* Now that the save buffer is emptied, let's write the input 22968651Skris buffer if a NL was found and there is anything to write. */ 23068651Skris if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) 23168651Skris { 232100928Snectar#if 0 23368651SkrisBIO_write(b->next_bio, "<*<", 3); 23468651Skris#endif 23568651Skris i=BIO_write(b->next_bio,in,p - in); 23668651Skris if (i <= 0) 23768651Skris { 23868651Skris BIO_copy_next_retry(b); 239100928Snectar#if 0 24068651SkrisBIO_write(b->next_bio, ">*>", 3); 24168651Skris#endif 24268651Skris if (i < 0) return((num > 0)?num:i); 24368651Skris if (i == 0) return(num); 24468651Skris } 245100928Snectar#if 0 24668651SkrisBIO_write(b->next_bio, ">*>", 3); 24768651Skris#endif 24868651Skris num+=i; 24968651Skris in+=i; 25068651Skris inl-=i; 25168651Skris } 25268651Skris } 25368651Skris while(foundnl && inl > 0); 25468651Skris /* We've written as much as we can. The rest of the input buffer, if 25568651Skris any, is text that doesn't and with a NL and therefore needs to be 25668651Skris saved for the next trip. */ 25768651Skris if (inl > 0) 25868651Skris { 25968651Skris memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 26068651Skris ctx->obuf_len += inl; 26168651Skris num += inl; 26268651Skris } 26368651Skris return num; 26468651Skris } 26568651Skris 26668651Skrisstatic long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 26768651Skris { 26868651Skris BIO *dbio; 26968651Skris BIO_LINEBUFFER_CTX *ctx; 27068651Skris long ret=1; 27168651Skris char *p; 27268651Skris int r; 27368651Skris int obs; 27468651Skris 27568651Skris ctx=(BIO_LINEBUFFER_CTX *)b->ptr; 27668651Skris 27768651Skris switch (cmd) 27868651Skris { 27968651Skris case BIO_CTRL_RESET: 28068651Skris ctx->obuf_len=0; 28168651Skris if (b->next_bio == NULL) return(0); 28268651Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 28368651Skris break; 28468651Skris case BIO_CTRL_INFO: 28568651Skris ret=(long)ctx->obuf_len; 28668651Skris break; 28768651Skris case BIO_CTRL_WPENDING: 28868651Skris ret=(long)ctx->obuf_len; 28968651Skris if (ret == 0) 29068651Skris { 29168651Skris if (b->next_bio == NULL) return(0); 29268651Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 29368651Skris } 29468651Skris break; 29568651Skris case BIO_C_SET_BUFF_SIZE: 29668651Skris obs=(int)num; 29768651Skris p=ctx->obuf; 29868651Skris if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) 29968651Skris { 30068651Skris p=(char *)OPENSSL_malloc((int)num); 30168651Skris if (p == NULL) 30268651Skris goto malloc_error; 30368651Skris } 30468651Skris if (ctx->obuf != p) 30568651Skris { 30668651Skris if (ctx->obuf_len > obs) 30768651Skris { 30868651Skris ctx->obuf_len = obs; 30968651Skris } 31068651Skris memcpy(p, ctx->obuf, ctx->obuf_len); 31168651Skris OPENSSL_free(ctx->obuf); 31268651Skris ctx->obuf=p; 31368651Skris ctx->obuf_size=obs; 31468651Skris } 31568651Skris break; 31668651Skris case BIO_C_DO_STATE_MACHINE: 31768651Skris if (b->next_bio == NULL) return(0); 31868651Skris BIO_clear_retry_flags(b); 31968651Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 32068651Skris BIO_copy_next_retry(b); 32168651Skris break; 32268651Skris 32368651Skris case BIO_CTRL_FLUSH: 32468651Skris if (b->next_bio == NULL) return(0); 32568651Skris if (ctx->obuf_len <= 0) 32668651Skris { 32768651Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 32868651Skris break; 32968651Skris } 33068651Skris 33168651Skris for (;;) 33268651Skris { 33368651Skris BIO_clear_retry_flags(b); 33468651Skris if (ctx->obuf_len > 0) 33568651Skris { 33668651Skris r=BIO_write(b->next_bio, 33768651Skris ctx->obuf, ctx->obuf_len); 33868651Skris#if 0 33968651Skrisfprintf(stderr,"FLUSH %3d -> %3d\n",ctx->obuf_len,r); 34068651Skris#endif 34168651Skris BIO_copy_next_retry(b); 34268651Skris if (r <= 0) return((long)r); 34368651Skris if (r < ctx->obuf_len) 34468651Skris memmove(ctx->obuf, ctx->obuf + r, 34568651Skris ctx->obuf_len - r); 34668651Skris ctx->obuf_len-=r; 34768651Skris } 34868651Skris else 34968651Skris { 35068651Skris ctx->obuf_len=0; 35168651Skris ret=1; 35268651Skris break; 35368651Skris } 35468651Skris } 35568651Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 35668651Skris break; 35768651Skris case BIO_CTRL_DUP: 35868651Skris dbio=(BIO *)ptr; 35968651Skris if ( !BIO_set_write_buffer_size(dbio,ctx->obuf_size)) 36068651Skris ret=0; 36168651Skris break; 36268651Skris default: 36368651Skris if (b->next_bio == NULL) return(0); 36468651Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 36568651Skris break; 36668651Skris } 36768651Skris return(ret); 36868651Skrismalloc_error: 36968651Skris BIOerr(BIO_F_LINEBUFFER_CTRL,ERR_R_MALLOC_FAILURE); 37068651Skris return(0); 37168651Skris } 37268651Skris 37368651Skrisstatic long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 37468651Skris { 37568651Skris long ret=1; 37668651Skris 37768651Skris if (b->next_bio == NULL) return(0); 37868651Skris switch (cmd) 37968651Skris { 38068651Skris default: 38168651Skris ret=BIO_callback_ctrl(b->next_bio,cmd,fp); 38268651Skris break; 38368651Skris } 38468651Skris return(ret); 38568651Skris } 38668651Skris 38768651Skrisstatic int linebuffer_gets(BIO *b, char *buf, int size) 38868651Skris { 38968651Skris if (b->next_bio == NULL) return(0); 39068651Skris return(BIO_gets(b->next_bio,buf,size)); 39168651Skris } 39268651Skris 39368651Skrisstatic int linebuffer_puts(BIO *b, const char *str) 39468651Skris { 39568651Skris return(linebuffer_write(b,str,strlen(str))); 39668651Skris } 39768651Skris 398