This commit was generated by cvs2svn to track changes on a CVS vendor
[openssl.git] / crypto / bio / bio_lib.c
1 /* crypto/bio/bio_lib.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 "crypto.h"
62 #include "cryptlib.h"
63 #include "bio.h"
64 #include "stack.h"
65
66 static STACK *bio_meth=NULL;
67 static int bio_meth_num=0;
68
69 BIO *BIO_new(method)
70 BIO_METHOD *method;
71         {
72         BIO *ret=NULL;
73
74         ret=(BIO *)Malloc(sizeof(BIO));
75         if (ret == NULL)
76                 {
77                 BIOerr(BIO_F_BIO_NEW,ERR_R_MALLOC_FAILURE);
78                 return(NULL);
79                 }
80         if (!BIO_set(ret,method))
81                 {
82                 Free(ret);
83                 ret=NULL;
84                 }
85         return(ret);
86         }
87
88 int BIO_set(bio,method)
89 BIO *bio;
90 BIO_METHOD *method;
91         {
92         bio->method=method;
93         bio->callback=NULL;
94         bio->cb_arg=NULL;
95         bio->init=0;
96         bio->shutdown=1;
97         bio->flags=0;
98         bio->retry_reason=0;
99         bio->num=0;
100         bio->ptr=NULL;
101         bio->prev_bio=NULL;
102         bio->next_bio=NULL;
103         bio->references=1;
104         bio->num_read=0L;
105         bio->num_write=0L;
106         CRYPTO_new_ex_data(bio_meth,(char *)bio,&bio->ex_data);
107         if (method->create != NULL)
108                 if (!method->create(bio))
109                         return(0);
110         return(1);
111         }
112
113 int BIO_free(a)
114 BIO *a;
115         {
116         int ret=0,i;
117
118         if (a == NULL) return(0);
119
120         i=CRYPTO_add(&a->references,-1,CRYPTO_LOCK_BIO);
121 #ifdef REF_PRINT
122         REF_PRINT("BIO",a);
123 #endif
124         if (i > 0) return(1);
125 #ifdef REF_CHECK
126         if (i < 0)
127                 {
128                 fprintf(stderr,"BIO_free, bad reference count\n");
129                 abort();
130                 }
131 #endif
132         if ((a->callback != NULL) &&
133                 ((i=(int)a->callback(a,BIO_CB_FREE,NULL,0,0L,1L)) <= 0))
134                         return(i);
135
136         CRYPTO_free_ex_data(bio_meth,(char *)a,&a->ex_data);
137
138         if ((a->method == NULL) || (a->method->destroy == NULL)) return(1);
139         ret=a->method->destroy(a);
140         Free(a);
141         return(1);
142         }
143
144 int BIO_read(b,out,outl)
145 BIO *b;
146 char *out;
147 int outl;
148         {
149         int i;
150         long (*cb)();
151
152         if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL))
153                 {
154                 BIOerr(BIO_F_BIO_READ,BIO_R_UNSUPPORTED_METHOD);
155                 return(-2);
156                 }
157
158         cb=b->callback;
159         if ((cb != NULL) &&
160                 ((i=(int)cb(b,BIO_CB_READ,out,outl,0L,1L)) <= 0))
161                         return(i);
162
163         if (!b->init)
164                 {
165                 BIOerr(BIO_F_BIO_READ,BIO_R_UNINITALISED);
166                 return(-2);
167                 }
168
169         i=b->method->bread(b,out,outl);
170         if (i > 0) b->num_read+=(unsigned long)i;
171
172         if (cb != NULL)
173                 i=(int)cb(b,BIO_CB_READ|BIO_CB_RETURN,out,outl,
174                         0L,(long)i);
175         return(i);
176         }
177
178 int BIO_write(b,in,inl)
179 BIO *b;
180 char *in;
181 int inl;
182         {
183         int i;
184         long (*cb)();
185
186         if (b == NULL)
187                 return(0);
188
189         cb=b->callback;
190         if ((b->method == NULL) || (b->method->bwrite == NULL))
191                 {
192                 BIOerr(BIO_F_BIO_WRITE,BIO_R_UNSUPPORTED_METHOD);
193                 return(-2);
194                 }
195
196         if ((cb != NULL) &&
197                 ((i=(int)cb(b,BIO_CB_WRITE,in,inl,0L,1L)) <= 0))
198                         return(i);
199
200         if (!b->init)
201                 {
202                 BIOerr(BIO_F_BIO_WRITE,BIO_R_UNINITALISED);
203                 return(-2);
204                 }
205
206         i=b->method->bwrite(b,in,inl);
207         if (i > 0) b->num_write+=(unsigned long)i;
208
209         if (cb != NULL)
210                 i=(int)cb(b,BIO_CB_WRITE|BIO_CB_RETURN,in,inl,
211                         0L,(long)i);
212         return(i);
213         }
214
215 int BIO_puts(b,in)
216 BIO *b;
217 char *in;
218         {
219         int i;
220         long (*cb)();
221
222         if ((b == NULL) || (b->method == NULL) || (b->method->bputs == NULL))
223                 {
224                 BIOerr(BIO_F_BIO_PUTS,BIO_R_UNSUPPORTED_METHOD);
225                 return(-2);
226                 }
227
228         cb=b->callback;
229
230         if ((cb != NULL) &&
231                 ((i=(int)cb(b,BIO_CB_PUTS,in,0,0L,1L)) <= 0))
232                         return(i);
233
234         if (!b->init)
235                 {
236                 BIOerr(BIO_F_BIO_PUTS,BIO_R_UNINITALISED);
237                 return(-2);
238                 }
239
240         i=b->method->bputs(b,in);
241
242         if (cb != NULL)
243                 i=(int)cb(b,BIO_CB_PUTS|BIO_CB_RETURN,in,0,
244                         0L,(long)i);
245         return(i);
246         }
247
248 int BIO_gets(b,in,inl)
249 BIO *b;
250 char *in;
251 int inl;
252         {
253         int i;
254         long (*cb)();
255
256         if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL))
257                 {
258                 BIOerr(BIO_F_BIO_GETS,BIO_R_UNSUPPORTED_METHOD);
259                 return(-2);
260                 }
261
262         cb=b->callback;
263
264         if ((cb != NULL) &&
265                 ((i=(int)cb(b,BIO_CB_GETS,in,inl,0L,1L)) <= 0))
266                         return(i);
267
268         if (!b->init)
269                 {
270                 BIOerr(BIO_F_BIO_GETS,BIO_R_UNINITALISED);
271                 return(-2);
272                 }
273
274         i=b->method->bgets(b,in,inl);
275
276         if (cb != NULL)
277                 i=(int)cb(b,BIO_CB_GETS|BIO_CB_RETURN,in,inl,
278                         0L,(long)i);
279         return(i);
280         }
281
282 long BIO_int_ctrl(b,cmd,larg,iarg)
283 BIO *b;
284 int cmd;
285 long larg;
286 int iarg;
287         {
288         int i;
289
290         i=iarg;
291         return(BIO_ctrl(b,cmd,larg,(char *)&i));
292         }
293
294 char *BIO_ptr_ctrl(b,cmd,larg)
295 BIO *b;
296 int cmd;
297 long larg;
298         {
299         char *p=NULL;
300
301         if (BIO_ctrl(b,cmd,larg,(char *)&p) <= 0)
302                 return(NULL);
303         else
304                 return(p);
305         }
306
307 long BIO_ctrl(b,cmd,larg,parg)
308 BIO *b;
309 int cmd;
310 long larg;
311 char *parg;
312         {
313         long ret;
314         long (*cb)();
315
316         if (b == NULL) return(0);
317
318         if ((b->method == NULL) || (b->method->ctrl == NULL))
319                 {
320                 BIOerr(BIO_F_BIO_CTRL,BIO_R_UNSUPPORTED_METHOD);
321                 return(-2);
322                 }
323
324         cb=b->callback;
325
326         if ((cb != NULL) &&
327                 ((ret=cb(b,BIO_CB_CTRL,parg,cmd,larg,1L)) <= 0))
328                 return(ret);
329
330         ret=b->method->ctrl(b,cmd,larg,parg);
331
332         if (cb != NULL)
333                 ret=cb(b,BIO_CB_CTRL|BIO_CB_RETURN,parg,cmd,
334                         larg,ret);
335         return(ret);
336         }
337
338 /* put the 'bio' on the end of b's list of operators */
339 BIO *BIO_push(b,bio)
340 BIO *b,*bio;
341         {
342         BIO *lb;
343
344         if (b == NULL) return(bio);
345         lb=b;
346         while (lb->next_bio != NULL)
347                 lb=lb->next_bio;
348         lb->next_bio=bio;
349         if (bio != NULL)
350                 bio->prev_bio=lb;
351         /* called to do internal processing */
352         BIO_ctrl(b,BIO_CTRL_PUSH,0,NULL);
353         return(b);
354         }
355
356 /* Remove the first and return the rest */
357 BIO *BIO_pop(b)
358 BIO *b;
359         {
360         BIO *ret;
361
362         if (b == NULL) return(NULL);
363         ret=b->next_bio;
364
365         if (b->prev_bio != NULL)
366                 b->prev_bio->next_bio=b->next_bio;
367         if (b->next_bio != NULL)
368                 b->next_bio->prev_bio=b->prev_bio;
369
370         b->next_bio=NULL;
371         b->prev_bio=NULL;
372         BIO_ctrl(b,BIO_CTRL_POP,0,NULL);
373         return(ret);
374         }
375
376 BIO *BIO_get_retry_BIO(bio,reason)
377 BIO *bio;
378 int *reason;
379         {
380         BIO *b,*last;
381
382         b=last=bio;
383         for (;;)
384                 {
385                 if (!BIO_should_retry(b)) break;
386                 last=b;
387                 b=b->next_bio;
388                 if (b == NULL) break;
389                 }
390         if (reason != NULL) *reason=last->retry_reason;
391         return(last);
392         }
393
394 int BIO_get_retry_reason(bio)
395 BIO *bio;
396         {
397         return(bio->retry_reason);
398         }
399
400 BIO *BIO_find_type(bio,type)
401 BIO *bio;
402 int type;
403         {
404         int mt,mask;
405
406         mask=type&0xff;
407         do      {
408                 if (bio->method != NULL)
409                         {
410                         mt=bio->method->type;
411
412                         if (!mask)
413                                 {
414                                 if (mt & type) return(bio);
415                                 }
416                         else if (mt == type)
417                                 return(bio);
418                         }
419                 bio=bio->next_bio;
420                 } while (bio != NULL);
421         return(NULL);
422         }
423
424 void BIO_free_all(bio)
425 BIO *bio;
426         {
427         BIO *b;
428         int ref;
429
430         while (bio != NULL)
431                 {
432                 b=bio;
433                 ref=b->references;
434                 bio=bio->next_bio;
435                 BIO_free(b);
436                 /* Since ref count > 1, don't free anyone else. */
437                 if (ref > 1) break;
438                 }
439         }
440
441 BIO *BIO_dup_chain(in)
442 BIO *in;
443         {
444         BIO *ret=NULL,*eoc=NULL,*bio,*new;
445
446         for (bio=in; bio != NULL; bio=bio->next_bio)
447                 {
448                 if ((new=BIO_new(bio->method)) == NULL) goto err;
449                 new->callback=bio->callback;
450                 new->cb_arg=bio->cb_arg;
451                 new->init=bio->init;
452                 new->shutdown=bio->shutdown;
453                 new->flags=bio->flags;
454
455                 /* This will let SSL_s_sock() work with stdin/stdout */
456                 new->num=bio->num;
457
458                 if (!BIO_dup_state(bio,(char *)new))
459                         {
460                         BIO_free(new);
461                         goto err;
462                         }
463
464                 /* copy app data */
465                 if (!CRYPTO_dup_ex_data(bio_meth,&new->ex_data,&bio->ex_data))
466                         goto err;
467
468                 if (ret == NULL)
469                         {
470                         eoc=new;
471                         ret=eoc;
472                         }
473                 else
474                         {
475                         BIO_push(eoc,new);
476                         eoc=new;
477                         }
478                 }
479         return(ret);
480 err:
481         if (ret != NULL)
482                 BIO_free(ret);
483         return(NULL);   
484         }
485
486 void BIO_copy_next_retry(b)
487 BIO *b;
488         {
489         BIO_set_flags(b,BIO_get_retry_flags(b->next_bio));
490         b->retry_reason=b->next_bio->retry_reason;
491         }
492
493 int BIO_get_ex_new_index(argl,argp,new_func,dup_func,free_func)
494 long argl;
495 char *argp;
496 int (*new_func)();
497 int (*dup_func)();
498 void (*free_func)();
499         {
500         bio_meth_num++;
501         return(CRYPTO_get_ex_new_index(bio_meth_num-1,&bio_meth,
502                 argl,argp,new_func,dup_func,free_func));
503         }
504
505 int BIO_set_ex_data(bio,idx,data)
506 BIO *bio;
507 int idx;
508 char *data;
509         {
510         return(CRYPTO_set_ex_data(&(bio->ex_data),idx,data));
511         }
512
513 char *BIO_get_ex_data(bio,idx)
514 BIO *bio;
515 int idx;
516         {
517         return(CRYPTO_get_ex_data(&(bio->ex_data),idx));
518         }
519