ec0f7eb0b7ee21ba436a620d1a62b57021083400
[dragonfly.git] / crypto / openssl-0.9 / crypto / bio / bf_lbuf.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 <openssl/bio.h>
63 #include <openssl/evp.h>
64
65 static int linebuffer_write(BIO *h, const char *buf,int num);
66 static int linebuffer_read(BIO *h, char *buf, int size);
67 static int linebuffer_puts(BIO *h, const char *str);
68 static int linebuffer_gets(BIO *h, char *str, int size);
69 static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
70 static int linebuffer_new(BIO *h);
71 static int linebuffer_free(BIO *data);
72 static long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
73
74 /* A 10k maximum should be enough for most purposes */
75 #define DEFAULT_LINEBUFFER_SIZE 1024*10
76
77 /* #define DEBUG */
78
79 static BIO_METHOD methods_linebuffer=
80         {
81         BIO_TYPE_LINEBUFFER,
82         "linebuffer",
83         linebuffer_write,
84         linebuffer_read,
85         linebuffer_puts,
86         linebuffer_gets,
87         linebuffer_ctrl,
88         linebuffer_new,
89         linebuffer_free,
90         linebuffer_callback_ctrl,
91         };
92
93 BIO_METHOD *BIO_f_linebuffer(void)
94         {
95         return(&methods_linebuffer);
96         }
97
98 typedef struct bio_linebuffer_ctx_struct
99         {
100         char *obuf;             /* the output char array */
101         int obuf_size;          /* how big is the output buffer */
102         int obuf_len;           /* how many bytes are in it */
103         } BIO_LINEBUFFER_CTX;
104
105 static int linebuffer_new(BIO *bi)
106         {
107         BIO_LINEBUFFER_CTX *ctx;
108
109         ctx=(BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX));
110         if (ctx == NULL) return(0);
111         ctx->obuf=(char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE);
112         if (ctx->obuf == NULL) { OPENSSL_free(ctx); return(0); }
113         ctx->obuf_size=DEFAULT_LINEBUFFER_SIZE;
114         ctx->obuf_len=0;
115
116         bi->init=1;
117         bi->ptr=(char *)ctx;
118         bi->flags=0;
119         return(1);
120         }
121
122 static int linebuffer_free(BIO *a)
123         {
124         BIO_LINEBUFFER_CTX *b;
125
126         if (a == NULL) return(0);
127         b=(BIO_LINEBUFFER_CTX *)a->ptr;
128         if (b->obuf != NULL) OPENSSL_free(b->obuf);
129         OPENSSL_free(a->ptr);
130         a->ptr=NULL;
131         a->init=0;
132         a->flags=0;
133         return(1);
134         }
135         
136 static int linebuffer_read(BIO *b, char *out, int outl)
137         {
138         int ret=0;
139  
140         if (out == NULL) return(0);
141         if (b->next_bio == NULL) return(0);
142         ret=BIO_read(b->next_bio,out,outl);
143         BIO_clear_retry_flags(b);
144         BIO_copy_next_retry(b);
145         return(ret);
146         }
147
148 static int linebuffer_write(BIO *b, const char *in, int inl)
149         {
150         int i,num=0,foundnl;
151         BIO_LINEBUFFER_CTX *ctx;
152
153         if ((in == NULL) || (inl <= 0)) return(0);
154         ctx=(BIO_LINEBUFFER_CTX *)b->ptr;
155         if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
156
157         BIO_clear_retry_flags(b);
158
159         do
160                 {
161                 const char *p;
162
163                 for(p = in; p < in + inl && *p != '\n'; p++)
164                         ;
165                 if (*p == '\n')
166                         {
167                         p++;
168                         foundnl = 1;
169                         }
170                 else
171                         foundnl = 0;
172
173                 /* If a NL was found and we already have text in the save
174                    buffer, concatenate them and write */
175                 while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len)
176                         && ctx->obuf_len > 0)
177                         {
178                         int orig_olen = ctx->obuf_len;
179                         
180                         i = ctx->obuf_size - ctx->obuf_len;
181                         if (p - in > 0)
182                                 {
183                                 if (i >= p - in)
184                                         {
185                                         memcpy(&(ctx->obuf[ctx->obuf_len]),
186                                                 in,p - in);
187                                         ctx->obuf_len += p - in;
188                                         inl -= p - in;
189                                         num += p - in;
190                                         in = p;
191                                         }
192                                 else
193                                         {
194                                         memcpy(&(ctx->obuf[ctx->obuf_len]),
195                                                 in,i);
196                                         ctx->obuf_len += i;
197                                         inl -= i;
198                                         in += i;
199                                         num += i;
200                                         }
201                                 }
202
203 #if 0
204 BIO_write(b->next_bio, "<*<", 3);
205 #endif
206                         i=BIO_write(b->next_bio,
207                                 ctx->obuf, ctx->obuf_len);
208                         if (i <= 0)
209                                 {
210                                 ctx->obuf_len = orig_olen;
211                                 BIO_copy_next_retry(b);
212
213 #if 0
214 BIO_write(b->next_bio, ">*>", 3);
215 #endif
216                                 if (i < 0) return((num > 0)?num:i);
217                                 if (i == 0) return(num);
218                                 }
219 #if 0
220 BIO_write(b->next_bio, ">*>", 3);
221 #endif
222                         if (i < ctx->obuf_len)
223                                 memmove(ctx->obuf, ctx->obuf + i,
224                                         ctx->obuf_len - i);
225                         ctx->obuf_len-=i;
226                         }
227
228                 /* Now that the save buffer is emptied, let's write the input
229                    buffer if a NL was found and there is anything to write. */
230                 if ((foundnl || p - in > ctx->obuf_size) && p - in > 0)
231                         {
232 #if 0
233 BIO_write(b->next_bio, "<*<", 3);
234 #endif
235                         i=BIO_write(b->next_bio,in,p - in);
236                         if (i <= 0)
237                                 {
238                                 BIO_copy_next_retry(b);
239 #if 0
240 BIO_write(b->next_bio, ">*>", 3);
241 #endif
242                                 if (i < 0) return((num > 0)?num:i);
243                                 if (i == 0) return(num);
244                                 }
245 #if 0
246 BIO_write(b->next_bio, ">*>", 3);
247 #endif
248                         num+=i;
249                         in+=i;
250                         inl-=i;
251                         }
252                 }
253         while(foundnl && inl > 0);
254         /* We've written as much as we can.  The rest of the input buffer, if
255            any, is text that doesn't and with a NL and therefore needs to be
256            saved for the next trip. */
257         if (inl > 0)
258                 {
259                 memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl);
260                 ctx->obuf_len += inl;
261                 num += inl;
262                 }
263         return num;
264         }
265
266 static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr)
267         {
268         BIO *dbio;
269         BIO_LINEBUFFER_CTX *ctx;
270         long ret=1;
271         char *p;
272         int r;
273         int obs;
274
275         ctx=(BIO_LINEBUFFER_CTX *)b->ptr;
276
277         switch (cmd)
278                 {
279         case BIO_CTRL_RESET:
280                 ctx->obuf_len=0;
281                 if (b->next_bio == NULL) return(0);
282                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
283                 break;
284         case BIO_CTRL_INFO:
285                 ret=(long)ctx->obuf_len;
286                 break;
287         case BIO_CTRL_WPENDING:
288                 ret=(long)ctx->obuf_len;
289                 if (ret == 0)
290                         {
291                         if (b->next_bio == NULL) return(0);
292                         ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
293                         }
294                 break;
295         case BIO_C_SET_BUFF_SIZE:
296                 obs=(int)num;
297                 p=ctx->obuf;
298                 if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size))
299                         {
300                         p=(char *)OPENSSL_malloc((int)num);
301                         if (p == NULL)
302                                 goto malloc_error;
303                         }
304                 if (ctx->obuf != p)
305                         {
306                         if (ctx->obuf_len > obs)
307                                 {
308                                 ctx->obuf_len = obs;
309                                 }
310                         memcpy(p, ctx->obuf, ctx->obuf_len);
311                         OPENSSL_free(ctx->obuf);
312                         ctx->obuf=p;
313                         ctx->obuf_size=obs;
314                         }
315                 break;
316         case BIO_C_DO_STATE_MACHINE:
317                 if (b->next_bio == NULL) return(0);
318                 BIO_clear_retry_flags(b);
319                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
320                 BIO_copy_next_retry(b);
321                 break;
322
323         case BIO_CTRL_FLUSH:
324                 if (b->next_bio == NULL) return(0);
325                 if (ctx->obuf_len <= 0)
326                         {
327                         ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
328                         break;
329                         }
330
331                 for (;;)
332                         {
333                         BIO_clear_retry_flags(b);
334                         if (ctx->obuf_len > 0)
335                                 {
336                                 r=BIO_write(b->next_bio,
337                                         ctx->obuf, ctx->obuf_len);
338 #if 0
339 fprintf(stderr,"FLUSH %3d -> %3d\n",ctx->obuf_len,r);
340 #endif
341                                 BIO_copy_next_retry(b);
342                                 if (r <= 0) return((long)r);
343                                 if (r < ctx->obuf_len)
344                                         memmove(ctx->obuf, ctx->obuf + r,
345                                                 ctx->obuf_len - r);
346                                 ctx->obuf_len-=r;
347                                 }
348                         else
349                                 {
350                                 ctx->obuf_len=0;
351                                 ret=1;
352                                 break;
353                                 }
354                         }
355                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
356                 break;
357         case BIO_CTRL_DUP:
358                 dbio=(BIO *)ptr;
359                 if (    !BIO_set_write_buffer_size(dbio,ctx->obuf_size))
360                         ret=0;
361                 break;
362         default:
363                 if (b->next_bio == NULL) return(0);
364                 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
365                 break;
366                 }
367         return(ret);
368 malloc_error:
369         BIOerr(BIO_F_LINEBUFFER_CTRL,ERR_R_MALLOC_FAILURE);
370         return(0);
371         }
372
373 static long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
374         {
375         long ret=1;
376
377         if (b->next_bio == NULL) return(0);
378         switch (cmd)
379                 {
380         default:
381                 ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
382                 break;
383                 }
384         return(ret);
385         }
386
387 static int linebuffer_gets(BIO *b, char *buf, int size)
388         {
389         if (b->next_bio == NULL) return(0);
390         return(BIO_gets(b->next_bio,buf,size));
391         }
392
393 static int linebuffer_puts(BIO *b, const char *str)
394         {
395         return(linebuffer_write(b,str,strlen(str)));
396         }
397