BIO pairs.
[openssl.git] / crypto / bio / bss_bio.c
1 /* crypto/bio/bss_bio.c  -*- Mode: C; c-file-style: "eay" -*- */
2
3 /* Special method for a BIO where the other endpoint is also a BIO
4  * of this kind, handled by the same thread (i.e. the "peer" is actually
5  * ourselves, wearing a different hat).
6  * Such "BIO pairs" are mainly for using the SSL library with I/O interfaces
7  * for which no specific BIO method is available.
8  * See ssl/ssltest.c for some hints on how this can be used. */
9
10 #include <assert.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <openssl/bio.h>
15 #include <openssl/err.h>
16 #include <openssl/crypto.h>
17
18 static int bio_new(BIO *bio);
19 static int bio_free(BIO *bio);
20 static int bio_read(BIO *bio, char *buf, int size);
21 static int bio_write(BIO *bio, char *buf, int num);
22 static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr);
23 static int bio_puts(BIO *bio, char *str);
24
25 static int bio_make_pair(BIO *bio1, BIO *bio2);
26 static void bio_destroy_pair(BIO *bio);
27
28 static BIO_METHOD methods_biop =
29 {
30         BIO_TYPE_BIO,
31         "BIO pair",
32         bio_write,
33         bio_read,
34         bio_puts,
35         NULL /* no bio_gets */,
36         bio_ctrl,
37         bio_new,
38         bio_free
39 };
40
41 BIO_METHOD *BIO_s_bio(void)
42         {
43         return &methods_biop;
44         }
45
46 struct bio_bio_st
47 {
48         BIO *peer;     /* NULL if buf == NULL.
49                         * If peer != NULL, then peer->ptr is also a bio_bio_st,
50                         * and its "peer" member points back to us.
51                         * peer != NULL iff init != 0 in the BIO. */
52         
53         /* This is for what we write (i.e. reading uses peer's struct): */
54         int closed;     /* valid iff peer != NULL */
55         size_t len;     /* valid iff buf != NULL; 0 if peer == NULL */
56         size_t offset;  /* valid iff buf != NULL; 0 if len == 0 */
57         size_t size;
58         char *buf;      /* "size" elements (if != NULL) */
59
60         size_t request; /* valid iff peer != NULL; 0 if len != 0;
61                          * otherwise set by peer to number of bytes
62                          * it (unsuccesfully) tried to read. */
63 };
64
65 static int bio_new(BIO *bio)
66         {
67         struct bio_bio_st *b;
68         
69         b = Malloc(sizeof *b);
70         if (b == NULL)
71                 return 0;
72
73         b->peer = NULL;
74         b->size = 17*1024; /* enough for one TLS record (just a default) */
75         b->buf = NULL;
76
77         bio->ptr = b;
78         return 1;
79         }
80
81
82 static int bio_free(BIO *bio)
83         {
84         struct bio_bio_st *b;
85
86         if (bio == NULL)
87                 return 0;
88         b = bio->ptr;
89
90         assert(b != NULL);
91
92         if (b->peer)
93                 bio_destroy_pair(bio);
94         
95         if (b->buf != NULL)
96                 {
97                 Free(b->buf);
98                 }
99
100         Free(b);
101
102         return 1;
103         }
104
105
106
107 static int bio_read(BIO *bio, char *buf, int size_)
108         {
109         size_t size = size_;
110         size_t rest;
111         struct bio_bio_st *b, *peer_b;
112
113         BIO_clear_retry_flags(bio);
114
115         if (!bio->init)
116                 return 0;
117
118         b = bio->ptr;
119         assert(b != NULL);
120         assert(b->peer != NULL);
121         peer_b = b->peer->ptr;
122         assert(peer_b != NULL);
123         assert(peer_b->buf != NULL);
124
125         peer_b->request = 0; /* will be set in "retry_read" situation */
126
127         if (buf == NULL || size == 0)
128                 return 0;
129
130         if (peer_b->len == 0)
131                 {
132                 if (peer_b->closed)
133                         return 0; /* writer has closed, and no data is left */
134                 else
135                         {
136                         BIO_set_retry_read(bio); /* buffer is empty */
137                         if (size <= peer_b->size)
138                                 peer_b->request = size;
139                         else
140                                 peer_b->request = peer_b->size; /* don't ask for more than
141                                                                  * the peer can deliver
142                                                                  * in one write */
143                         return -1;
144                         }
145                 }
146
147         /* we can read */
148         if (peer_b->len < size)
149                 size = peer_b->len;
150
151         /* now read "size" bytes */
152         
153         rest = size;
154         
155         assert(rest > 0);
156         do /* one or two iterations */
157                 {
158                 size_t chunk;
159                 
160                 assert(rest <= peer_b->len);
161                 if (peer_b->offset + rest <= peer_b->size)
162                         chunk = rest;
163                 else
164                         /* wrap around ring buffer */
165                         chunk = peer_b->size - peer_b->offset;
166                 assert(peer_b->offset + chunk <= peer_b->size);
167                 
168                 memcpy(buf, peer_b->buf + peer_b->offset, chunk);
169                 
170                 peer_b->len -= chunk;
171                 if (peer_b->len)
172                         {
173                         peer_b->offset += chunk;
174                         assert(peer_b->offset <= peer_b->size);
175                         if (peer_b->offset == peer_b->size)
176                                 peer_b->offset = 0;
177                         buf += chunk;
178                         }
179                 else
180                         {
181                         /* buffer now empty, no need to advance "buf" */
182                         assert(chunk == rest);
183                         peer_b->offset = 0;
184                         }
185                 rest -= chunk;
186                 }
187         while (rest);
188         
189         peer_b->request -= size;
190         return size;
191         }
192
193 static int bio_write(BIO *bio, char *buf, int num_)
194         {
195         size_t num = num_;
196         size_t rest;
197         struct bio_bio_st *b;
198
199         BIO_clear_retry_flags(bio);
200
201         if (!bio->init || buf == NULL || num == 0)
202                 return 0;
203
204         b = bio->ptr;           
205         assert(b != NULL);
206         assert(b->peer != NULL);
207         assert(b->buf != NULL);
208
209         b->request = 0;
210         if (b->closed)
211                 {
212                 /* we already closed */
213                 BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE);
214                 return -1;
215                 }
216
217         assert(b->len <= b->size);
218
219         if (b->len == b->size)
220                 {
221                 BIO_set_retry_write(bio); /* buffer is full */
222                 return -1;
223                 }
224
225         /* we can write */
226         if (num > b->size - b->len)
227                 num = b->size - b->len;
228         
229         /* now write "num" bytes */
230
231         rest = num;
232         
233         assert(rest > 0);
234         do /* one or two iterations */
235                 {
236                 size_t write_offset;
237                 size_t chunk;
238
239                 assert(b->len + rest <= b->size);
240
241                 write_offset = b->offset + b->len;
242                 if (write_offset >= b->size)
243                         write_offset -= b->size;
244                 /* b->buf[write_offset] is the first byte we can write to. */
245
246                 if (write_offset + rest <= b->size)
247                         chunk = rest;
248                 else
249                         /* wrap around ring buffer */
250                         chunk = b->size - write_offset;
251                 
252                 memcpy(b->buf + write_offset, buf, chunk);
253                 
254                 b->len += chunk;
255
256                 assert(b->len <= b->size);
257                 
258                 rest -= chunk;
259                 buf += chunk;
260                 }
261         while (rest);
262
263         return num;
264         }
265
266
267 static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr)
268         {
269         long ret;
270         struct bio_bio_st *b = bio->ptr;
271         
272         assert(b != NULL);
273
274         switch (cmd)
275                 {
276         /* specific CTRL codes */
277
278         case BIO_C_SET_WRITE_BUF_SIZE:
279                 if (b->peer)
280                         {
281                         BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE);
282                         ret = 0;
283                         }
284                 else
285                         {
286                         size_t new_size = num;
287
288                         if (b->size != new_size)
289                                 {
290                                 if (b->buf) 
291                                         {
292                                         Free(b->buf);
293                                         b->buf = NULL;
294                                         }
295                                 b->size = new_size;
296                                 }
297                         ret = 1;
298                         }
299                 break;
300
301         case BIO_C_GET_WRITE_BUF_SIZE:
302                 num = (long) b->size;
303
304         case BIO_C_MAKE_BIO_PAIR:
305                 {
306                 BIO *other_bio = ptr;
307                 
308                 if (bio_make_pair(bio, other_bio))
309                         ret = 1;
310                 else
311                         ret = 0;
312                 }
313                 break;
314                 
315         case BIO_C_DESTROY_BIO_PAIR:
316                 /* Effects both BIOs in the pair -- call just once!
317                  * Or let BIO_free(bio1); BIO_free(bio2); do the job. */
318                 bio_destroy_pair(bio);
319                 ret = 1;
320                 break;
321
322         case BIO_C_GET_WRITE_GUARANTEE:
323                 /* How many bytes can the caller feed to the next write
324                  * withouth having to keep any? */
325                 if (b->peer == NULL || b->closed)
326                         ret = 0;
327                 else
328                         ret = (long) b->size - b->len;
329                 break;
330
331         case BIO_C_GET_READ_REQUEST:
332                 /* If the peer unsuccesfully tried to read, how many bytes
333                  * were requested?  (As with BIO_CTRL_PENDING, that number
334                  * can usually be treated as boolean.) */
335                 ret = (long) b->request;
336                 break;
337
338         case BIO_C_SHUTDOWN_WR:
339                 /* similar to shutdown(..., SHUT_WR) */
340                 b->closed = 1;
341                 ret = 1;
342                 break;
343
344
345         /* standard CTRL codes follow */
346
347         case BIO_CTRL_RESET:
348                 if (b->buf != NULL)
349                         {
350                         b->len = 0;
351                         b->offset = 0;
352                         }
353                 ret = 0;
354                 break;          
355
356         case BIO_CTRL_GET_CLOSE:
357                 ret = bio->shutdown;
358                 break;
359
360         case BIO_CTRL_SET_CLOSE:
361                 bio->shutdown = (int) num;
362                 ret = 1;
363                 break;
364
365         case BIO_CTRL_PENDING:
366                 if (b->peer != NULL)
367                         {
368                         struct bio_bio_st *peer_b =b->peer->ptr;
369                         
370                         ret = (long) peer_b->len;
371                         }
372                 else
373                         ret = 0;
374                 break;
375
376         case BIO_CTRL_WPENDING:
377                 if (b->buf != NULL)
378                         ret = (long) b->len;
379                 else
380                         ret = 0;
381                 break;
382
383         case BIO_CTRL_DUP:
384                 /* See BIO_dup_chain for circumstances we have to expect. */
385                 {
386                 BIO *other_bio = ptr;
387                 struct bio_bio_st *other_b;
388                 
389                 assert(other_bio != NULL);
390                 other_b = other_bio->ptr;
391                 assert(other_b != NULL);
392                 
393                 assert(other_b->buf == NULL); /* other_bio is always fresh */
394
395                 other_b->size = b->size;
396                 }
397
398                 ret = 1;
399                 break;
400
401         case BIO_CTRL_FLUSH:
402                 ret = 1;
403                 break;
404
405         case BIO_CTRL_EOF:
406                 {
407                 BIO *other_bio = ptr;
408                 
409                 if (other_bio)
410                         {
411                         struct bio_bio_st *other_b = other_bio->ptr;
412                         
413                         assert(other_b != NULL);
414                         ret = other_b->len == 0 && other_b->closed;
415                         }
416                 else
417                         ret = 1;
418                 }
419                 break;
420
421         default:
422                 ret = 0;
423                 }
424         return ret;
425         }
426
427 static int bio_puts(BIO *bio, char *str)
428         {
429         return bio_write(bio, str, strlen(str));
430         }
431
432
433 static int bio_make_pair(BIO *bio1, BIO *bio2)
434         {
435         struct bio_bio_st *b1, *b2;
436
437         assert(bio1 != NULL);
438         assert(bio2 != NULL);
439
440         b1 = bio1->ptr;
441         b2 = bio2->ptr;
442         
443         if (b1->peer != NULL || b2->peer != NULL)
444                 {
445                 BIOerr(BIO_F_BIO_MAKE_PAIR, BIO_R_IN_USE);
446                 return 0;
447                 }
448         
449         if (b1->buf == NULL)
450                 {
451                 b1->buf = Malloc(b1->size);
452                 if (b1->buf == NULL)
453                         {
454                         BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE);
455                         return 0;
456                         }
457                 b1->len = 0;
458                 b1->offset = 0;
459                 }
460         
461         if (b2->buf == NULL)
462                 {
463                 b2->buf = Malloc(b2->size);
464                 if (b2->buf == NULL)
465                         {
466                         BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE);
467                         return 0;
468                         }
469                 b2->len = 0;
470                 b2->offset = 0;
471                 }
472         
473         b1->peer = bio2;
474         b1->closed = 0;
475         b1->request = 0;
476         b2->peer = bio1;
477         b2->closed = 0;
478         b2->request = 0;
479
480         bio1->init = 1;
481         bio2->init = 1;
482
483         return 1;
484         }
485
486 static void bio_destroy_pair(BIO *bio)
487         {
488         struct bio_bio_st *b = bio->ptr;
489
490         if (b != NULL)
491                 {
492                 BIO *peer_bio = b->peer;
493
494                 if (peer_bio != NULL)
495                         {
496                         struct bio_bio_st *peer_b = peer_bio->ptr;
497
498                         assert(peer_b != NULL);
499                         assert(peer_b->peer == bio);
500
501                         peer_b->peer = NULL;
502                         peer_bio->init = 0;
503                         assert(peer_b->buf != NULL);
504                         peer_b->len = 0;
505                         peer_b->offset = 0;
506                         
507                         b->peer = NULL;
508                         bio->init = 0;
509                         assert(b->buf != NULL);
510                         b->len = 0;
511                         b->offset = 0;
512                         }
513                 }
514         }
515  
516
517 /* Exported convenience functions */
518 int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1,
519         BIO **bio2_p, size_t writebuf2)
520          {
521          BIO *bio1 = NULL, *bio2 = NULL;
522          long r;
523          int ret = 0;
524
525          bio1 = BIO_new(BIO_s_bio());
526          if (bio1 == NULL)
527                  goto err;
528          bio2 = BIO_new(BIO_s_bio());
529          if (bio2 == NULL)
530                  goto err;
531
532          if (writebuf1)
533                  {
534                  r = BIO_set_write_buf_size(bio1, writebuf1);
535                  if (!r)
536                          goto err;
537                  }
538          if (writebuf2)
539                  {
540                  r = BIO_set_write_buf_size(bio2, writebuf2);
541                  if (!r)
542                          goto err;
543                  }
544
545          r = BIO_make_bio_pair(bio1, bio2);
546          if (!r)
547                  goto err;
548          ret = 1;
549
550  err:
551          if (ret == 0)
552                  {
553                  if (bio1)
554                          {
555                          BIO_free(bio1);
556                          bio1 = NULL;
557                          }
558                  if (bio2)
559                          {
560                          BIO_free(bio2);
561                          bio2 = NULL;
562                          }
563                  }
564
565          *bio1_p = bio1;
566          *bio2_p = bio2;
567          return ret;
568          }
569
570 size_t BIO_ctrl_get_write_guarantee(BIO *bio)
571     {
572         return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
573         }
574
575 size_t BIO_ctrl_read_request(BIO *bio)
576     {
577         return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
578         }