afa9cd27b74cd4af01009a9b77e1904726d3c41c
[openssl.git] / crypto / bio / bf_buff.c
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 "bio.h"
63 #include "evp.h"
64
65 #ifndef NOPROTO
66 static int buffer_write(BIO *h,char *buf,int num);
67 static int buffer_read(BIO *h,char *buf,int size);
68 static int buffer_puts(BIO *h,char *str);
69 static int buffer_gets(BIO *h,char *str,int size);
70 static long buffer_ctrl(BIO *h,int cmd,long arg1,char *arg2);
71 static int buffer_new(BIO *h);
72 static int buffer_free(BIO *data);
73 #else
74 static int buffer_write();
75 static int buffer_read();
76 static int buffer_puts();
77 static int buffer_gets();
78 static long buffer_ctrl();
79 static int buffer_new();
80 static int buffer_free();
81 #endif
82
83 #define DEFAULT_BUFFER_SIZE     1024
84
85 static BIO_METHOD methods_buffer=
86         {
87         BIO_TYPE_BUFFER,
88         "buffer",
89         buffer_write,
90         buffer_read,
91         buffer_puts,
92         buffer_gets,
93         buffer_ctrl,
94         buffer_new,
95         buffer_free,
96         };
97
98 BIO_METHOD *BIO_f_buffer()
99         {
100         return(&methods_buffer);
101         }
102
103 static int buffer_new(bi)
104 BIO *bi;
105         {
106         BIO_F_BUFFER_CTX *ctx;
107
108         ctx=(BIO_F_BUFFER_CTX *)Malloc(sizeof(BIO_F_BUFFER_CTX));
109         if (ctx == NULL) return(0);
110         ctx->ibuf=(char *)Malloc(DEFAULT_BUFFER_SIZE);
111         if (ctx->ibuf == NULL) { Free(ctx); return(0); }
112         ctx->obuf=(char *)Malloc(DEFAULT_BUFFER_SIZE);
113         if (ctx->obuf == NULL) { Free(ctx->ibuf); Free(ctx); return(0); }
114         ctx->ibuf_size=DEFAULT_BUFFER_SIZE;
115         ctx->obuf_size=DEFAULT_BUFFER_SIZE;
116         ctx->ibuf_len=0;
117         ctx->ibuf_off=0;
118         ctx->obuf_len=0;
119         ctx->obuf_off=0;
120
121         bi->init=1;
122         bi->ptr=(char *)ctx;
123         bi->flags=0;
124         return(1);
125         }
126
127 static int buffer_free(a)
128 BIO *a;
129         {
130         BIO_F_BUFFER_CTX *b;
131
132         if (a == NULL) return(0);
133         b=(BIO_F_BUFFER_CTX *)a->ptr;
134         if (b->ibuf != NULL) Free(b->ibuf);
135         if (b->obuf != NULL) Free(b->obuf);
136         Free(a->ptr);
137         a->ptr=NULL;
138         a->init=0;
139         a->flags=0;
140         return(1);
141         }
142         
143 static int buffer_read(b,out,outl)
144 BIO *b;
145 char *out;
146 int outl;
147         {
148         int i,num=0;
149         BIO_F_BUFFER_CTX *ctx;
150
151         if (out == NULL) return(0);
152         ctx=(BIO_F_BUFFER_CTX *)b->ptr;
153
154         if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
155         num=0;
156         BIO_clear_retry_flags(b);
157
158 start:
159         i=ctx->ibuf_len;
160         /* If there is stuff left over, grab it */
161         if (i != 0)
162                 {
163                 if (i > outl) i=outl;
164                 memcpy(out,&(ctx->ibuf[ctx->ibuf_off]),i);
165                 ctx->ibuf_off+=i;
166                 ctx->ibuf_len-=i;
167                 num+=i;
168                 if (outl == i)  return(num);
169                 outl-=i;
170                 out+=i;
171                 }
172
173         /* We may have done a partial read. try to do more.
174          * We have nothing in the buffer.
175          * If we get an error and have read some data, just return it
176          * and let them retry to get the error again.
177          * copy direct to parent address space */
178         if (outl > ctx->ibuf_size)
179                 {
180                 for (;;)
181                         {
182                         i=BIO_read(b->next_bio,out,outl);
183                         if (i <= 0)
184                                 {
185                                 BIO_copy_next_retry(b);
186                                 if (i < 0) return((num > 0)?num:i);
187                                 if (i == 0) return(num);
188                                 }
189                         num+=i;
190                         if (outl == i) return(num);
191                         out+=i;
192                         outl-=i;
193                         }
194                 }
195         /* else */
196
197         /* we are going to be doing some buffering */
198         i=BIO_read(b->next_bio,ctx->ibuf,ctx->ibuf_size);
199         if (i <= 0)
200                 {
201                 BIO_copy_next_retry(b);
202                 if (i < 0) return((num > 0)?num:i);
203                 if (i == 0) return(num);
204                 }
205         ctx->ibuf_off=0;
206         ctx->ibuf_len=i;
207
208         /* Lets re-read using ourselves :-) */
209         goto start;
210         }
211
212 static int buffer_write(b,in,inl)
213 BIO *b;
214 char *in;
215 int inl;
216         {
217         int i,num=0;
218         BIO_F_BUFFER_CTX *ctx;
219
220         if ((in == NULL) || (inl <= 0)) return(0);
221         ctx=(BIO_F_BUFFER_CTX *)b->ptr;
222         if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
223
224         BIO_clear_retry_flags(b);
225 start:
226         i=ctx->obuf_size-(ctx->obuf_len+ctx->obuf_off);
227         /* add to buffer and return */
228         if (i >= inl)
229                 {
230                 memcpy(&(ctx->obuf[ctx->obuf_len]),in,inl);
231                 ctx->obuf_len+=inl;
232                 return(num+inl);
233                 }
234         /* else */
235         /* stuff already in buffer, so add to it first, then flush */
236         if (ctx->obuf_len != 0)
237                 {
238                 if (i > 0) /* lets fill it up if we can */
239                         {
240                         memcpy(&(ctx->obuf[ctx->obuf_len]),in,i);
241                         in+=i;
242                         inl-=i;
243                         num+=i;
244                         ctx->obuf_len+=i;
245                         }
246                 /* we now have a full buffer needing flushing */
247                 for (;;)
248                         {
249                         i=BIO_write(b->next_bio,&(ctx->obuf[ctx->obuf_off]),
250                                 ctx->obuf_len);
251                         if (i <= 0)
252                                 {
253                                 BIO_copy_next_retry(b);
254
255                                 if (i < 0) return((num > 0)?num:i);
256                                 if (i == 0) return(num);
257                                 }
258                         ctx->obuf_off+=i;
259                         ctx->obuf_len-=i;
260                         if (ctx->obuf_len == 0) break;
261                         }
262                 }
263         /* we only get here if the buffer has been flushed and we
264          * still have stuff to write */
265         ctx->obuf_off=0;
266
267         /* we now have inl bytes to write */
268         while (inl >= ctx->obuf_size)
269                 {
270                 i=BIO_write(b->next_bio,in,inl);
271                 if (i <= 0)
272                         {
273                         BIO_copy_next_retry(b);
274                         if (i < 0) return((num > 0)?num:i);
275                         if (i == 0) return(num);
276                         }
277                 num+=i;
278                 in+=i;
279                 inl-=i;
280                 if (inl == 0) return(num);
281                 }
282
283         /* copy the rest into the buffer since we have only a small 
284          * amount left */
285         goto start;
286         }
287
288 static long buffer_ctrl(b,cmd,num,ptr)
289 BIO *b;
290 int cmd;
291 long num;
292 char *ptr;
293         {
294         BIO *dbio;
295         BIO_F_BUFFER_CTX *ctx;
296         long ret=1;
297         char *p1,*p2;
298         int r,i,*ip;
299         int ibs,obs;
300
301         ctx=(BIO_F_BUFFER_CTX *)b->ptr;
302
303         switch (cmd)
304                 {
305         case BIO_CTRL_RESET:
306                 ctx->ibuf_off=0;
307                 ctx->ibuf_len=0;
308                 ctx->obuf_off=0;
309                 ctx->obuf_len=0;
310                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
311                 break;
312         case BIO_CTRL_INFO:
313                 ret=(long)ctx->obuf_len;
314                 break;
315         case BIO_C_GET_BUFF_NUM_LINES:
316                 ret=0;
317                 p1=ctx->ibuf;
318                 for (i=ctx->ibuf_off; i<ctx->ibuf_len; i++)
319                         {
320                         if (p1[i] == '\n') ret++;
321                         }
322                 break;
323         case BIO_CTRL_WPENDING:
324                 ret=(long)ctx->obuf_len;
325                 if (ret == 0)
326                         ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
327                 break;
328         case BIO_CTRL_PENDING:
329                 ret=(long)ctx->ibuf_len;
330                 if (ret == 0)
331                         ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
332                 break;
333         case BIO_C_SET_BUFF_READ_DATA:
334                 if (num > ctx->ibuf_size)
335                         {
336                         p1=Malloc((int)num);
337                         if (p1 == NULL) goto malloc_error;
338                         if (ctx->ibuf != NULL) Free(ctx->ibuf);
339                         ctx->ibuf=p1;
340                         }
341                 ctx->ibuf_off=0;
342                 ctx->ibuf_len=(int)num;
343                 memcpy(ctx->ibuf,ptr,(int)num);
344                 ret=1;
345                 break;
346         case BIO_C_SET_BUFF_SIZE:
347                 if (ptr != NULL)
348                         {
349                         ip=(int *)ptr;
350                         if (*ip == 0)
351                                 {
352                                 ibs=(int)num;
353                                 obs=ctx->obuf_size;
354                                 }
355                         else /* if (*ip == 1) */
356                                 {
357                                 ibs=ctx->ibuf_size;
358                                 obs=(int)num;
359                                 }
360                         }
361                 else
362                         {
363                         ibs=(int)num;
364                         obs=(int)num;
365                         }
366                 p1=ctx->ibuf;
367                 p2=ctx->obuf;
368                 if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size))
369                         {
370                         p1=(char *)Malloc((int)num);
371                         if (p1 == NULL) goto malloc_error;
372                         }
373                 if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size))
374                         {
375                         p2=(char *)Malloc((int)num);
376                         if (p2 == NULL)
377                                 {
378                                 if (p1 != ctx->ibuf) Free(p1);
379                                 goto malloc_error;
380                                 }
381                         }
382                 if (ctx->ibuf != p1)
383                         {
384                         Free(ctx->ibuf);
385                         ctx->ibuf=p1;
386                         ctx->ibuf_off=0;
387                         ctx->ibuf_len=0;
388                         ctx->ibuf_size=ibs;
389                         }
390                 if (ctx->obuf != p2)
391                         {
392                         Free(ctx->obuf);
393                         ctx->obuf=p2;
394                         ctx->obuf_off=0;
395                         ctx->obuf_len=0;
396                         ctx->obuf_size=obs;
397                         }
398                 break;
399         case BIO_C_DO_STATE_MACHINE:
400                 BIO_clear_retry_flags(b);
401                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
402                 BIO_copy_next_retry(b);
403                 break;
404
405         case BIO_CTRL_FLUSH:
406                 if (ctx->obuf_len <= 0)
407                         {
408                         ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
409                         break;
410                         }
411
412                 for (;;)
413                         {
414                         BIO_clear_retry_flags(b);
415                         if (ctx->obuf_len > ctx->obuf_off)
416                                 {
417                                 r=BIO_write(b->next_bio,
418                                         &(ctx->obuf[ctx->obuf_off]),
419                                         ctx->obuf_len-ctx->obuf_off);
420 #if 0
421 fprintf(stderr,"FLUSH [%3d] %3d -> %3d\n",ctx->obuf_off,ctx->obuf_len-ctx->obuf_off,r);
422 #endif
423                                 BIO_copy_next_retry(b);
424                                 if (r <= 0) return((long)r);
425                                 ctx->obuf_off+=r;
426                                 }
427                         else
428                                 {
429                                 ctx->obuf_len=0;
430                                 ctx->obuf_off=0;
431                                 ret=1;
432                                 break;
433                                 }
434                         }
435                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
436                 break;
437         case BIO_CTRL_DUP:
438                 dbio=(BIO *)ptr;
439                 if (    !BIO_set_read_buffer_size(dbio,ctx->ibuf_size) ||
440                         !BIO_set_write_buffer_size(dbio,ctx->obuf_size))
441                         ret=0;
442                 break;
443         default:
444                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
445                 break;
446                 }
447         return(ret);
448 malloc_error:
449         BIOerr(BIO_F_BUFFER_CTRL,ERR_R_MALLOC_FAILURE);
450         return(0);
451         }
452
453 static int buffer_gets(b,buf,size)
454 BIO *b;
455 char *buf;
456 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) || (i == size))
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                                 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(b,str)
508 BIO *b;
509 char *str;
510         {
511         return(BIO_write(b,str,strlen(str)));
512         }
513