bf_buff.c revision 7b476c43f6a45574eb34697244b592e7b09f05a3
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
64static int buffer_write(BIO *h, const char *buf,int num);
65static int buffer_read(BIO *h, char *buf, int size);
66static int buffer_puts(BIO *h, const char *str);
67static int buffer_gets(BIO *h, char *str, int size);
68static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
69static int buffer_new(BIO *h);
70static int buffer_free(BIO *data);
71static long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
72#define DEFAULT_BUFFER_SIZE	4096
73
74static 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
88BIO_METHOD *BIO_f_buffer(void)
89	{
90	return(&methods_buffer);
91	}
92
93static 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
116static 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
131static 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
143start:
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
197static 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);
207start:
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_off+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_off+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
270static 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=0; i<ctx->ibuf_len; i++)
298			{
299			if (p1[ctx->ibuf_off + 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 > 0)
403				{
404				r=BIO_write(b->next_bio,
405					&(ctx->obuf[ctx->obuf_off]),
406					ctx->obuf_len);
407#if 0
408fprintf(stderr,"FLUSH [%3d] %3d -> %3d\n",ctx->obuf_off,ctx->obuf_len,r);
409#endif
410				BIO_copy_next_retry(b);
411				if (r <= 0) return((long)r);
412				ctx->obuf_off+=r;
413				ctx->obuf_len-=r;
414				}
415			else
416				{
417				ctx->obuf_len=0;
418				ctx->obuf_off=0;
419				ret=1;
420				break;
421				}
422			}
423		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
424		break;
425	case BIO_CTRL_DUP:
426		dbio=(BIO *)ptr;
427		if (	!BIO_set_read_buffer_size(dbio,ctx->ibuf_size) ||
428			!BIO_set_write_buffer_size(dbio,ctx->obuf_size))
429			ret=0;
430		break;
431	default:
432		if (b->next_bio == NULL) return(0);
433		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
434		break;
435		}
436	return(ret);
437malloc_error:
438	BIOerr(BIO_F_BUFFER_CTRL,ERR_R_MALLOC_FAILURE);
439	return(0);
440	}
441
442static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
443	{
444	long ret=1;
445
446	if (b->next_bio == NULL) return(0);
447	switch (cmd)
448		{
449	default:
450		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
451		break;
452		}
453	return(ret);
454	}
455
456static int buffer_gets(BIO *b, char *buf, int size)
457	{
458	BIO_F_BUFFER_CTX *ctx;
459	int num=0,i,flag;
460	char *p;
461
462	ctx=(BIO_F_BUFFER_CTX *)b->ptr;
463	size--; /* reserve space for a '\0' */
464	BIO_clear_retry_flags(b);
465
466	for (;;)
467		{
468		if (ctx->ibuf_len > 0)
469			{
470			p= &(ctx->ibuf[ctx->ibuf_off]);
471			flag=0;
472			for (i=0; (i<ctx->ibuf_len) && (i<size); i++)
473				{
474				*(buf++)=p[i];
475				if (p[i] == '\n')
476					{
477					flag=1;
478					i++;
479					break;
480					}
481				}
482			num+=i;
483			size-=i;
484			ctx->ibuf_len-=i;
485			ctx->ibuf_off+=i;
486			if (flag || size == 0)
487				{
488				*buf='\0';
489				return(num);
490				}
491			}
492		else	/* read another chunk */
493			{
494			i=BIO_read(b->next_bio,ctx->ibuf,ctx->ibuf_size);
495			if (i <= 0)
496				{
497				BIO_copy_next_retry(b);
498				*buf='\0';
499				if (i < 0) return((num > 0)?num:i);
500				if (i == 0) return(num);
501				}
502			ctx->ibuf_len=i;
503			ctx->ibuf_off=0;
504			}
505		}
506	}
507
508static int buffer_puts(BIO *b, const char *str)
509	{
510	return(buffer_write(b,str,strlen(str)));
511	}
512
513