diff options
author | Bodo Möller <bodo@openssl.org> | 1999-06-12 01:03:40 +0000 |
---|---|---|
committer | Bodo Möller <bodo@openssl.org> | 1999-06-12 01:03:40 +0000 |
commit | 95d29597b7cc2ec3653811b1a659094b4831f96b (patch) | |
tree | 0959b7b48af2cbf172b0f6a2ab35f86e503c3ef6 /crypto | |
parent | 9bce3070acf81a2890ec7a6c94b97094691b5038 (diff) |
BIO pairs.
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/bio/bio.h | 36 | ||||
-rw-r--r-- | crypto/bio/bio_err.c | 1 | ||||
-rw-r--r-- | crypto/bio/bio_lib.c | 16 | ||||
-rw-r--r-- | crypto/bio/bss_bio.c | 349 |
4 files changed, 377 insertions, 25 deletions
diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h index f75e77b941..5d1654aaef 100644 --- a/crypto/bio/bio.h +++ b/crypto/bio/bio.h @@ -64,6 +64,7 @@ extern "C" { #endif #include <stdio.h> +#include <stdlib.h> #include <openssl/crypto.h> /* These are the 'types' of BIOs */ @@ -317,6 +318,15 @@ typedef struct bio_f_buffer_ctx_struct #define BIO_C_GET_SOCKS 134 #define BIO_C_SET_SOCKS 135 +#define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */ +#define BIO_C_GET_WRITE_BUF_SIZE 137 +#define BIO_C_MAKE_BIO_PAIR 138 +#define BIO_C_DESTROY_BIO_PAIR 139 +#define BIO_C_GET_WRITE_GUARANTEE 140 +#define BIO_C_GET_READ_REQUEST 141 +#define BIO_C_SHUTDOWN_WR 142 + + #define BIO_set_app_data(s,arg) BIO_set_ex_data(s,0,(char *)arg) #define BIO_get_app_data(s) BIO_get_ex_data(s,0) @@ -431,6 +441,9 @@ int BIO_read_filename(BIO *b,const char *name); #define BIO_get_close(b) (int)BIO_ctrl(b,BIO_CTRL_GET_CLOSE,0,NULL) #define BIO_pending(b) (int)BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL) #define BIO_wpending(b) (int)BIO_ctrl(b,BIO_CTRL_WPENDING,0,NULL) +/* ...pending macros have inappropriate return type */ +size_t BIO_ctrl_pending(BIO *b); +size_t BIO_ctrl_wpending(BIO *b); #define BIO_flush(b) (int)BIO_ctrl(b,BIO_CTRL_FLUSH,0,NULL) #define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0,(char *)cbp) #define BIO_set_info_callback(b,cb) (int)BIO_ctrl(b,BIO_CTRL_SET_CALLBACK,0,(char *)cb) @@ -438,6 +451,19 @@ int BIO_read_filename(BIO *b,const char *name); /* For the BIO_f_buffer() type */ #define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL) +/* For BIO_s_bio() */ +#define BIO_set_write_buf_size(b,size) (int)BIO_ctrl(b,BIO_C_SET_WRITE_BUF_SIZE,size,NULL) +#define BIO_get_write_buf_size(b,size) (size_t)BIO_ctrl(b,BIO_C_GET_WRITE_BUF_SIZE,size,NULL) +#define BIO_make_bio_pair(b1,b2) (int)BIO_ctrl(b1,BIO_C_MAKE_BIO_PAIR,0,b2) +#define BIO_destroy_bio_pair(b) (int)BIO_ctrl(b,BIO_C_DESTROY_BIO_PAIR,0,NULL) +/* macros with inappropriate type -- but ...pending macros use int too: */ +#define BIO_get_write_guarantee(b) (int)BIO_ctrl(b,BIO_C_GET_WRITE_GUARANTEE,0,NULL) +#define BIO_get_read_request(b) (int)BIO_ctrl(b,BIO_C_GET_READ_REQUEST,0,NULL) +size_t BIO_ctrl_get_write_guarantee(BIO *b); +size_t BIO_ctrl_get_read_request(BIO *b); + + + #ifdef NO_STDIO #define NO_FP_API #endif @@ -473,7 +499,7 @@ int BIO_read(BIO *b, void *data, int len); int BIO_gets(BIO *bp,char *buf, int size); int BIO_write(BIO *b, const char *data, int len); int BIO_puts(BIO *bp,const char *buf); -long BIO_ctrl(BIO *bp,int cmd,long larg,char *parg); +long BIO_ctrl(BIO *bp,int cmd,long larg,void *parg); char * BIO_ptr_ctrl(BIO *bp,int cmd,long larg); long BIO_int_ctrl(BIO *bp,int cmd,long larg,int iarg); BIO * BIO_push(BIO *b,BIO *append); @@ -538,6 +564,13 @@ BIO *BIO_new_fd(int fd, int close_flag); BIO *BIO_new_connect(char *host_port); BIO *BIO_new_accept(char *host_port); +int BIO_new_bio_pair(BIO **bio1, size_t writebuf1, + BIO **bio2, size_t writebuf2); +/* If successful, returns 1 and in *bio1, *bio2 two BIO pair endpoints. + * Otherwise returns 0 and sets *bio1 and *bio2 to NULL. + * Size 0 uses default value. + */ + void BIO_copy_next_retry(BIO *b); long BIO_ghbn_ctrl(int cmd,int iarg,char *parg); @@ -579,6 +612,7 @@ int BIO_printf(BIO *bio, ...); #define BIO_R_ACCEPT_ERROR 100 #define BIO_R_BAD_FOPEN_MODE 101 #define BIO_R_BAD_HOSTNAME_LOOKUP 102 +#define BIO_R_BROKEN_PIPE 124 #define BIO_R_CONNECT_ERROR 103 #define BIO_R_ERROR_SETTING_NBIO 104 #define BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET 105 diff --git a/crypto/bio/bio_err.c b/crypto/bio/bio_err.c index badbfc1919..e31bf32aa4 100644 --- a/crypto/bio/bio_err.c +++ b/crypto/bio/bio_err.c @@ -95,6 +95,7 @@ static ERR_STRING_DATA BIO_str_reasons[]= {BIO_R_ACCEPT_ERROR ,"accept error"}, {BIO_R_BAD_FOPEN_MODE ,"bad fopen mode"}, {BIO_R_BAD_HOSTNAME_LOOKUP ,"bad hostname lookup"}, +{BIO_R_BROKEN_PIPE ,"broken pipe"}, {BIO_R_CONNECT_ERROR ,"connect error"}, {BIO_R_ERROR_SETTING_NBIO ,"error setting nbio"}, {BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET,"error setting nbio on accepted socket"}, diff --git a/crypto/bio/bio_lib.c b/crypto/bio/bio_lib.c index 62d26992af..b72688ea90 100644 --- a/crypto/bio/bio_lib.c +++ b/crypto/bio/bio_lib.c @@ -290,7 +290,7 @@ char *BIO_ptr_ctrl(BIO *b, int cmd, long larg) return(p); } -long BIO_ctrl(BIO *b, int cmd, long larg, char *parg) +long BIO_ctrl(BIO *b, int cmd, long larg, void *parg) { long ret; long (*cb)(); @@ -317,6 +317,20 @@ long BIO_ctrl(BIO *b, int cmd, long larg, char *parg) return(ret); } +/* It is unfortunate to duplicate in functions what the BIO_(w)pending macros + * do; but those macros have inappropriate return type, and for interfacing + * from other programming languages, C macros aren't much of a help anyway. */ +size_t BIO_ctrl_pending(BIO *bio) + { + return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL); + } + +size_t BIO_ctrl_wpending(BIO *bio) + { + return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL); + } + + /* put the 'bio' on the end of b's list of operators */ BIO *BIO_push(BIO *b, BIO *bio) { diff --git a/crypto/bio/bss_bio.c b/crypto/bio/bss_bio.c index f026d51807..ea9d5c714a 100644 --- a/crypto/bio/bss_bio.c +++ b/crypto/bio/bss_bio.c @@ -1,11 +1,11 @@ /* crypto/bio/bss_bio.c -*- Mode: C; c-file-style: "eay" -*- */ -/* *** Not yet finished (or even tested). *** */ - /* Special method for a BIO where the other endpoint is also a BIO - * of this kind, handled by the same thread. + * of this kind, handled by the same thread (i.e. the "peer" is actually + * ourselves, wearing a different hat). * Such "BIO pairs" are mainly for using the SSL library with I/O interfaces - * for which no specific BIO method is available. */ + * for which no specific BIO method is available. + * See ssl/ssltest.c for some hints on how this can be used. */ #include <assert.h> #include <stdlib.h> @@ -19,7 +19,7 @@ static int bio_new(BIO *bio); static int bio_free(BIO *bio); static int bio_read(BIO *bio, char *buf, int size); static int bio_write(BIO *bio, char *buf, int num); -static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr); +static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr); static int bio_puts(BIO *bio, char *str); static int bio_make_pair(BIO *bio1, BIO *bio2); @@ -74,6 +74,7 @@ static int bio_new(BIO *bio) b->size = 17*1024; /* enough for one TLS record (just a default) */ b->buf = NULL; + bio->ptr = b; return 1; } @@ -103,19 +104,167 @@ static int bio_free(BIO *bio) -static int bio_read(BIO *bio, char *buf, int size) +static int bio_read(BIO *bio, char *buf, int size_) { - /* XXX */ - return -1; + size_t size = size_; + size_t rest; + struct bio_bio_st *b, *peer_b; + + BIO_clear_retry_flags(bio); + + if (!bio->init) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + peer_b = b->peer->ptr; + assert(peer_b != NULL); + assert(peer_b->buf != NULL); + + peer_b->request = 0; /* will be set in "retry_read" situation */ + + if (buf == NULL || size == 0) + return 0; + + if (peer_b->len == 0) + { + if (peer_b->closed) + return 0; /* writer has closed, and no data is left */ + else + { + BIO_set_retry_read(bio); /* buffer is empty */ + if (size <= peer_b->size) + peer_b->request = size; + else + peer_b->request = peer_b->size; /* don't ask for more than + * the peer can deliver + * in one write */ + return -1; + } + } + + /* we can read */ + if (peer_b->len < size) + size = peer_b->len; + + /* now read "size" bytes */ + + rest = size; + + assert(rest > 0); + do /* one or two iterations */ + { + size_t chunk; + + assert(rest <= peer_b->len); + if (peer_b->offset + rest <= peer_b->size) + chunk = rest; + else + /* wrap around ring buffer */ + chunk = peer_b->size - peer_b->offset; + assert(peer_b->offset + chunk <= peer_b->size); + + memcpy(buf, peer_b->buf + peer_b->offset, chunk); + + peer_b->len -= chunk; + if (peer_b->len) + { + peer_b->offset += chunk; + assert(peer_b->offset <= peer_b->size); + if (peer_b->offset == peer_b->size) + peer_b->offset = 0; + buf += chunk; + } + else + { + /* buffer now empty, no need to advance "buf" */ + assert(chunk == rest); + peer_b->offset = 0; + } + rest -= chunk; + } + while (rest); + + peer_b->request -= size; + return size; } -static int bio_write(BIO *bio, char *buf, int num) +static int bio_write(BIO *bio, char *buf, int num_) { - /* XXX */ - return -1; - } + size_t num = num_; + size_t rest; + struct bio_bio_st *b; + + BIO_clear_retry_flags(bio); + + if (!bio->init || buf == NULL || num == 0) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + assert(b->buf != NULL); + + b->request = 0; + if (b->closed) + { + /* we already closed */ + BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE); + return -1; + } + + assert(b->len <= b->size); + + if (b->len == b->size) + { + BIO_set_retry_write(bio); /* buffer is full */ + return -1; + } + + /* we can write */ + if (num > b->size - b->len) + num = b->size - b->len; + + /* now write "num" bytes */ + + rest = num; -static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr) + assert(rest > 0); + do /* one or two iterations */ + { + size_t write_offset; + size_t chunk; + + assert(b->len + rest <= b->size); + + write_offset = b->offset + b->len; + if (write_offset >= b->size) + write_offset -= b->size; + /* b->buf[write_offset] is the first byte we can write to. */ + + if (write_offset + rest <= b->size) + chunk = rest; + else + /* wrap around ring buffer */ + chunk = b->size - write_offset; + + memcpy(b->buf + write_offset, buf, chunk); + + b->len += chunk; + + assert(b->len <= b->size); + + rest -= chunk; + buf += chunk; + } + while (rest); + + return num; + } + + +static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) { long ret; struct bio_bio_st *b = bio->ptr; @@ -124,13 +273,76 @@ static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr) switch (cmd) { - /* XXX Additional commands: */ - /* - Set buffer size */ - /* - make pair */ - /* - destroy pair */ - /* - get number of bytes that the next write will accept */ - /* - get number of bytes requested by peer */ - /* - send "close" */ + /* specific CTRL codes */ + + case BIO_C_SET_WRITE_BUF_SIZE: + if (b->peer) + { + BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE); + ret = 0; + } + else + { + size_t new_size = num; + + if (b->size != new_size) + { + if (b->buf) + { + Free(b->buf); + b->buf = NULL; + } + b->size = new_size; + } + ret = 1; + } + break; + + case BIO_C_GET_WRITE_BUF_SIZE: + num = (long) b->size; + + case BIO_C_MAKE_BIO_PAIR: + { + BIO *other_bio = ptr; + + if (bio_make_pair(bio, other_bio)) + ret = 1; + else + ret = 0; + } + break; + + case BIO_C_DESTROY_BIO_PAIR: + /* Effects both BIOs in the pair -- call just once! + * Or let BIO_free(bio1); BIO_free(bio2); do the job. */ + bio_destroy_pair(bio); + ret = 1; + break; + + case BIO_C_GET_WRITE_GUARANTEE: + /* How many bytes can the caller feed to the next write + * withouth having to keep any? */ + if (b->peer == NULL || b->closed) + ret = 0; + else + ret = (long) b->size - b->len; + break; + + case BIO_C_GET_READ_REQUEST: + /* If the peer unsuccesfully tried to read, how many bytes + * were requested? (As with BIO_CTRL_PENDING, that number + * can usually be treated as boolean.) */ + ret = (long) b->request; + break; + + case BIO_C_SHUTDOWN_WR: + /* similar to shutdown(..., SHUT_WR) */ + b->closed = 1; + ret = 1; + break; + + + /* standard CTRL codes follow */ case BIO_CTRL_RESET: if (b->buf != NULL) @@ -169,7 +381,20 @@ static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr) break; case BIO_CTRL_DUP: - /* XXX */ + /* See BIO_dup_chain for circumstances we have to expect. */ + { + BIO *other_bio = ptr; + struct bio_bio_st *other_b; + + assert(other_bio != NULL); + other_b = other_bio->ptr; + assert(other_b != NULL); + + assert(other_b->buf == NULL); /* other_bio is always fresh */ + + other_b->size = b->size; + } + ret = 1; break; @@ -177,6 +402,22 @@ static long bio_ctrl(BIO *bio, int cmd, long num, char *ptr) ret = 1; break; + case BIO_CTRL_EOF: + { + BIO *other_bio = ptr; + + if (other_bio) + { + struct bio_bio_st *other_b = other_bio->ptr; + + assert(other_b != NULL); + ret = other_b->len == 0 && other_b->closed; + } + else + ret = 1; + } + break; + default: ret = 0; } @@ -188,8 +429,6 @@ static int bio_puts(BIO *bio, char *str) return bio_write(bio, str, strlen(str)); } -/* Until bio_make_pair is used, make a dummy function use it for -pedantic */ -void dummy() { bio_make_pair(NULL,NULL); } static int bio_make_pair(BIO *bio1, BIO *bio2) { @@ -273,3 +512,67 @@ static void bio_destroy_pair(BIO *bio) } } } + + +/* Exported convenience functions */ +int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1, + BIO **bio2_p, size_t writebuf2) + { + BIO *bio1 = NULL, *bio2 = NULL; + long r; + int ret = 0; + + bio1 = BIO_new(BIO_s_bio()); + if (bio1 == NULL) + goto err; + bio2 = BIO_new(BIO_s_bio()); + if (bio2 == NULL) + goto err; + + if (writebuf1) + { + r = BIO_set_write_buf_size(bio1, writebuf1); + if (!r) + goto err; + } + if (writebuf2) + { + r = BIO_set_write_buf_size(bio2, writebuf2); + if (!r) + goto err; + } + + r = BIO_make_bio_pair(bio1, bio2); + if (!r) + goto err; + ret = 1; + + err: + if (ret == 0) + { + if (bio1) + { + BIO_free(bio1); + bio1 = NULL; + } + if (bio2) + { + BIO_free(bio2); + bio2 = NULL; + } + } + + *bio1_p = bio1; + *bio2_p = bio2; + return ret; + } + +size_t BIO_ctrl_get_write_guarantee(BIO *bio) + { + return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); + } + +size_t BIO_ctrl_read_request(BIO *bio) + { + return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); + } |