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