os/ossrv/ssl/libcrypto/src/crypto/bio/bf_buff.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* crypto/bio/bf_buff.c */
     2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
     3  * All rights reserved.
     4  *
     5  * This package is an SSL implementation written
     6  * by Eric Young (eay@cryptsoft.com).
     7  * The implementation was written so as to conform with Netscapes SSL.
     8  * 
     9  * This library is free for commercial and non-commercial use as long as
    10  * the following conditions are aheared to.  The following conditions
    11  * apply to all code found in this distribution, be it the RC4, RSA,
    12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
    13  * included with this distribution is covered by the same copyright terms
    14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
    15  * 
    16  * Copyright remains Eric Young's, and as such any Copyright notices in
    17  * the code are not to be removed.
    18  * If this package is used in a product, Eric Young should be given attribution
    19  * as the author of the parts of the library used.
    20  * This can be in the form of a textual message at program startup or
    21  * in documentation (online or textual) provided with the package.
    22  * 
    23  * Redistribution and use in source and binary forms, with or without
    24  * modification, are permitted provided that the following conditions
    25  * are met:
    26  * 1. Redistributions of source code must retain the copyright
    27  *    notice, this list of conditions and the following disclaimer.
    28  * 2. Redistributions in binary form must reproduce the above copyright
    29  *    notice, this list of conditions and the following disclaimer in the
    30  *    documentation and/or other materials provided with the distribution.
    31  * 3. All advertising materials mentioning features or use of this software
    32  *    must display the following acknowledgement:
    33  *    "This product includes cryptographic software written by
    34  *     Eric Young (eay@cryptsoft.com)"
    35  *    The word 'cryptographic' can be left out if the rouines from the library
    36  *    being used are not cryptographic related :-).
    37  * 4. If you include any Windows specific code (or a derivative thereof) from 
    38  *    the apps directory (application code) you must include an acknowledgement:
    39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
    40  * 
    41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
    42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    51  * SUCH DAMAGE.
    52  * 
    53  * The licence and distribution terms for any publically available version or
    54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
    55  * copied and put under another distribution licence
    56  * [including the GNU Public Licence.]
    57  */
    58 
    59 #include <stdio.h>
    60 #include <errno.h>
    61 #include "cryptlib.h"
    62 #include <openssl/bio.h>
    63 
    64 static int buffer_write(BIO *h, const char *buf,int num);
    65 static int buffer_read(BIO *h, char *buf, int size);
    66 static int buffer_puts(BIO *h, const char *str);
    67 static int buffer_gets(BIO *h, char *str, int size);
    68 static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
    69 static int buffer_new(BIO *h);
    70 static int buffer_free(BIO *data);
    71 static long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
    72 #define DEFAULT_BUFFER_SIZE	4096
    73 
    74 static BIO_METHOD methods_buffer=
    75 	{
    76 	BIO_TYPE_BUFFER,
    77 	"buffer",
    78 	buffer_write,
    79 	buffer_read,
    80 	buffer_puts,
    81 	buffer_gets,
    82 	buffer_ctrl,
    83 	buffer_new,
    84 	buffer_free,
    85 	buffer_callback_ctrl,
    86 	};
    87 
    88 EXPORT_C BIO_METHOD *BIO_f_buffer(void)
    89 	{
    90 	return(&methods_buffer);
    91 	}
    92 
    93 static int buffer_new(BIO *bi)
    94 	{
    95 	BIO_F_BUFFER_CTX *ctx;
    96 
    97 	ctx=(BIO_F_BUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX));
    98 	if (ctx == NULL) return(0);
    99 	ctx->ibuf=(char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
   100 	if (ctx->ibuf == NULL) { OPENSSL_free(ctx); return(0); }
   101 	ctx->obuf=(char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
   102 	if (ctx->obuf == NULL) { OPENSSL_free(ctx->ibuf); OPENSSL_free(ctx); return(0); }
   103 	ctx->ibuf_size=DEFAULT_BUFFER_SIZE;
   104 	ctx->obuf_size=DEFAULT_BUFFER_SIZE;
   105 	ctx->ibuf_len=0;
   106 	ctx->ibuf_off=0;
   107 	ctx->obuf_len=0;
   108 	ctx->obuf_off=0;
   109 
   110 	bi->init=1;
   111 	bi->ptr=(char *)ctx;
   112 	bi->flags=0;
   113 	return(1);
   114 	}
   115 
   116 static int buffer_free(BIO *a)
   117 	{
   118 	BIO_F_BUFFER_CTX *b;
   119 
   120 	if (a == NULL) return(0);
   121 	b=(BIO_F_BUFFER_CTX *)a->ptr;
   122 	if (b->ibuf != NULL) OPENSSL_free(b->ibuf);
   123 	if (b->obuf != NULL) OPENSSL_free(b->obuf);
   124 	OPENSSL_free(a->ptr);
   125 	a->ptr=NULL;
   126 	a->init=0;
   127 	a->flags=0;
   128 	return(1);
   129 	}
   130 	
   131 static int buffer_read(BIO *b, char *out, int outl)
   132 	{
   133 	int i,num=0;
   134 	BIO_F_BUFFER_CTX *ctx;
   135 
   136 	if (out == NULL) return(0);
   137 	ctx=(BIO_F_BUFFER_CTX *)b->ptr;
   138 
   139 	if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
   140 	num=0;
   141 	BIO_clear_retry_flags(b);
   142 
   143 start:
   144 	i=ctx->ibuf_len;
   145 	/* If there is stuff left over, grab it */
   146 	if (i != 0)
   147 		{
   148 		if (i > outl) i=outl;
   149 		memcpy(out,&(ctx->ibuf[ctx->ibuf_off]),i);
   150 		ctx->ibuf_off+=i;
   151 		ctx->ibuf_len-=i;
   152 		num+=i;
   153 		if (outl == i)  return(num);
   154 		outl-=i;
   155 		out+=i;
   156 		}
   157 
   158 	/* We may have done a partial read. try to do more.
   159 	 * We have nothing in the buffer.
   160 	 * If we get an error and have read some data, just return it
   161 	 * and let them retry to get the error again.
   162 	 * copy direct to parent address space */
   163 	if (outl > ctx->ibuf_size)
   164 		{
   165 		for (;;)
   166 			{
   167 			i=BIO_read(b->next_bio,out,outl);
   168 			if (i <= 0)
   169 				{
   170 				BIO_copy_next_retry(b);
   171 				if (i < 0) return((num > 0)?num:i);
   172 				if (i == 0) return(num);
   173 				}
   174 			num+=i;
   175 			if (outl == i) return(num);
   176 			out+=i;
   177 			outl-=i;
   178 			}
   179 		}
   180 	/* else */
   181 
   182 	/* we are going to be doing some buffering */
   183 	i=BIO_read(b->next_bio,ctx->ibuf,ctx->ibuf_size);
   184 	if (i <= 0)
   185 		{
   186 		BIO_copy_next_retry(b);
   187 		if (i < 0) return((num > 0)?num:i);
   188 		if (i == 0) return(num);
   189 		}
   190 	ctx->ibuf_off=0;
   191 	ctx->ibuf_len=i;
   192 
   193 	/* Lets re-read using ourselves :-) */
   194 	goto start;
   195 	}
   196 
   197 static int buffer_write(BIO *b, const char *in, int inl)
   198 	{
   199 	int i,num=0;
   200 	BIO_F_BUFFER_CTX *ctx;
   201 
   202 	if ((in == NULL) || (inl <= 0)) return(0);
   203 	ctx=(BIO_F_BUFFER_CTX *)b->ptr;
   204 	if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
   205 
   206 	BIO_clear_retry_flags(b);
   207 start:
   208 	i=ctx->obuf_size-(ctx->obuf_len+ctx->obuf_off);
   209 	/* add to buffer and return */
   210 	if (i >= inl)
   211 		{
   212 		memcpy(&(ctx->obuf[ctx->obuf_len]),in,inl);
   213 		ctx->obuf_len+=inl;
   214 		return(num+inl);
   215 		}
   216 	/* else */
   217 	/* stuff already in buffer, so add to it first, then flush */
   218 	if (ctx->obuf_len != 0)
   219 		{
   220 		if (i > 0) /* lets fill it up if we can */
   221 			{
   222 			memcpy(&(ctx->obuf[ctx->obuf_len]),in,i);
   223 			in+=i;
   224 			inl-=i;
   225 			num+=i;
   226 			ctx->obuf_len+=i;
   227 			}
   228 		/* we now have a full buffer needing flushing */
   229 		for (;;)
   230 			{
   231 			i=BIO_write(b->next_bio,&(ctx->obuf[ctx->obuf_off]),
   232 				ctx->obuf_len);
   233 			if (i <= 0)
   234 				{
   235 				BIO_copy_next_retry(b);
   236 
   237 				if (i < 0) return((num > 0)?num:i);
   238 				if (i == 0) return(num);
   239 				}
   240 			ctx->obuf_off+=i;
   241 			ctx->obuf_len-=i;
   242 			if (ctx->obuf_len == 0) break;
   243 			}
   244 		}
   245 	/* we only get here if the buffer has been flushed and we
   246 	 * still have stuff to write */
   247 	ctx->obuf_off=0;
   248 
   249 	/* we now have inl bytes to write */
   250 	while (inl >= ctx->obuf_size)
   251 		{
   252 		i=BIO_write(b->next_bio,in,inl);
   253 		if (i <= 0)
   254 			{
   255 			BIO_copy_next_retry(b);
   256 			if (i < 0) return((num > 0)?num:i);
   257 			if (i == 0) return(num);
   258 			}
   259 		num+=i;
   260 		in+=i;
   261 		inl-=i;
   262 		if (inl == 0) return(num);
   263 		}
   264 
   265 	/* copy the rest into the buffer since we have only a small 
   266 	 * amount left */
   267 	goto start;
   268 	}
   269 
   270 static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr)
   271 	{
   272 	BIO *dbio;
   273 	BIO_F_BUFFER_CTX *ctx;
   274 	long ret=1;
   275 	char *p1,*p2;
   276 	int r,i,*ip;
   277 	int ibs,obs;
   278 
   279 	ctx=(BIO_F_BUFFER_CTX *)b->ptr;
   280 
   281 	switch (cmd)
   282 		{
   283 	case BIO_CTRL_RESET:
   284 		ctx->ibuf_off=0;
   285 		ctx->ibuf_len=0;
   286 		ctx->obuf_off=0;
   287 		ctx->obuf_len=0;
   288 		if (b->next_bio == NULL) return(0);
   289 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
   290 		break;
   291 	case BIO_CTRL_INFO:
   292 		ret=(long)ctx->obuf_len;
   293 		break;
   294 	case BIO_C_GET_BUFF_NUM_LINES:
   295 		ret=0;
   296 		p1=ctx->ibuf;
   297 		for (i=ctx->ibuf_off; i<ctx->ibuf_len; i++)
   298 			{
   299 			if (p1[i] == '\n') ret++;
   300 			}
   301 		break;
   302 	case BIO_CTRL_WPENDING:
   303 		ret=(long)ctx->obuf_len;
   304 		if (ret == 0)
   305 			{
   306 			if (b->next_bio == NULL) return(0);
   307 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
   308 			}
   309 		break;
   310 	case BIO_CTRL_PENDING:
   311 		ret=(long)ctx->ibuf_len;
   312 		if (ret == 0)
   313 			{
   314 			if (b->next_bio == NULL) return(0);
   315 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
   316 			}
   317 		break;
   318 	case BIO_C_SET_BUFF_READ_DATA:
   319 		if (num > ctx->ibuf_size)
   320 			{
   321 			p1=OPENSSL_malloc((int)num);
   322 			if (p1 == NULL) goto malloc_error;
   323 			if (ctx->ibuf != NULL) OPENSSL_free(ctx->ibuf);
   324 			ctx->ibuf=p1;
   325 			}
   326 		ctx->ibuf_off=0;
   327 		ctx->ibuf_len=(int)num;
   328 		memcpy(ctx->ibuf,ptr,(int)num);
   329 		ret=1;
   330 		break;
   331 	case BIO_C_SET_BUFF_SIZE:
   332 		if (ptr != NULL)
   333 			{
   334 			ip=(int *)ptr;
   335 			if (*ip == 0)
   336 				{
   337 				ibs=(int)num;
   338 				obs=ctx->obuf_size;
   339 				}
   340 			else /* if (*ip == 1) */
   341 				{
   342 				ibs=ctx->ibuf_size;
   343 				obs=(int)num;
   344 				}
   345 			}
   346 		else
   347 			{
   348 			ibs=(int)num;
   349 			obs=(int)num;
   350 			}
   351 		p1=ctx->ibuf;
   352 		p2=ctx->obuf;
   353 		if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size))
   354 			{
   355 			p1=(char *)OPENSSL_malloc((int)num);
   356 			if (p1 == NULL) goto malloc_error;
   357 			}
   358 		if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size))
   359 			{
   360 			p2=(char *)OPENSSL_malloc((int)num);
   361 			if (p2 == NULL)
   362 				{
   363 				if (p1 != ctx->ibuf) OPENSSL_free(p1);
   364 				goto malloc_error;
   365 				}
   366 			}
   367 		if (ctx->ibuf != p1)
   368 			{
   369 			OPENSSL_free(ctx->ibuf);
   370 			ctx->ibuf=p1;
   371 			ctx->ibuf_off=0;
   372 			ctx->ibuf_len=0;
   373 			ctx->ibuf_size=ibs;
   374 			}
   375 		if (ctx->obuf != p2)
   376 			{
   377 			OPENSSL_free(ctx->obuf);
   378 			ctx->obuf=p2;
   379 			ctx->obuf_off=0;
   380 			ctx->obuf_len=0;
   381 			ctx->obuf_size=obs;
   382 			}
   383 		break;
   384 	case BIO_C_DO_STATE_MACHINE:
   385 		if (b->next_bio == NULL) return(0);
   386 		BIO_clear_retry_flags(b);
   387 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
   388 		BIO_copy_next_retry(b);
   389 		break;
   390 
   391 	case BIO_CTRL_FLUSH:
   392 		if (b->next_bio == NULL) return(0);
   393 		if (ctx->obuf_len <= 0)
   394 			{
   395 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
   396 			break;
   397 			}
   398 
   399 		for (;;)
   400 			{
   401 			BIO_clear_retry_flags(b);
   402 			if (ctx->obuf_len > ctx->obuf_off)
   403 				{
   404 				r=BIO_write(b->next_bio,
   405 					&(ctx->obuf[ctx->obuf_off]),
   406 					ctx->obuf_len-ctx->obuf_off);
   407 #if 0
   408 fprintf(stderr,"FLUSH [%3d] %3d -> %3d\n",ctx->obuf_off,ctx->obuf_len-ctx->obuf_off,r);
   409 #endif
   410 				BIO_copy_next_retry(b);
   411 				if (r <= 0) return((long)r);
   412 				ctx->obuf_off+=r;
   413 				}
   414 			else
   415 				{
   416 				ctx->obuf_len=0;
   417 				ctx->obuf_off=0;
   418 				ret=1;
   419 				break;
   420 				}
   421 			}
   422 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
   423 		break;
   424 	case BIO_CTRL_DUP:
   425 		dbio=(BIO *)ptr;
   426 		if (	!BIO_set_read_buffer_size(dbio,ctx->ibuf_size) ||
   427 			!BIO_set_write_buffer_size(dbio,ctx->obuf_size))
   428 			ret=0;
   429 		break;
   430 	default:
   431 		if (b->next_bio == NULL) return(0);
   432 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
   433 		break;
   434 		}
   435 	return(ret);
   436 malloc_error:
   437 	BIOerr(BIO_F_BUFFER_CTRL,ERR_R_MALLOC_FAILURE);
   438 	return(0);
   439 	}
   440 
   441 static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
   442 	{
   443 	long ret=1;
   444 
   445 	if (b->next_bio == NULL) return(0);
   446 	switch (cmd)
   447 		{
   448 	default:
   449 		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
   450 		break;
   451 		}
   452 	return(ret);
   453 	}
   454 
   455 static int buffer_gets(BIO *b, char *buf, int size)
   456 	{
   457 	BIO_F_BUFFER_CTX *ctx;
   458 	int num=0,i,flag;
   459 	char *p;
   460 
   461 	ctx=(BIO_F_BUFFER_CTX *)b->ptr;
   462 	size--; /* reserve space for a '\0' */
   463 	BIO_clear_retry_flags(b);
   464 
   465 	for (;;)
   466 		{
   467 		if (ctx->ibuf_len > 0)
   468 			{
   469 			p= &(ctx->ibuf[ctx->ibuf_off]);
   470 			flag=0;
   471 			for (i=0; (i<ctx->ibuf_len) && (i<size); i++)
   472 				{
   473 				*(buf++)=p[i];
   474 				if (p[i] == '\n')
   475 					{
   476 					flag=1;
   477 					i++;
   478 					break;
   479 					}
   480 				}
   481 			num+=i;
   482 			size-=i;
   483 			ctx->ibuf_len-=i;
   484 			ctx->ibuf_off+=i;
   485 			if (flag || size == 0)
   486 				{
   487 				*buf='\0';
   488 				return(num);
   489 				}
   490 			}
   491 		else	/* read another chunk */
   492 			{
   493 			i=BIO_read(b->next_bio,ctx->ibuf,ctx->ibuf_size);
   494 			if (i <= 0)
   495 				{
   496 				BIO_copy_next_retry(b);
   497 				*buf='\0';
   498 				if (i < 0) return((num > 0)?num:i);
   499 				if (i == 0) return(num);
   500 				}
   501 			ctx->ibuf_len=i;
   502 			ctx->ibuf_off=0;
   503 			}
   504 		}
   505 	}
   506 
   507 static int buffer_puts(BIO *b, const char *str)
   508 	{
   509 	return(buffer_write(b,str,strlen(str)));
   510 	}
   511