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