/** read from a mbuf. * (internal openssl use via the tls_mbuf method) * @return bytes read on success (0< ret <=dst_len), -1 on empty buffer & sets * should_retry_read, -1 on some other errors (w/o should_retry_read set). */ static int tls_bio_mbuf_read(BIO* b, char* dst, int dst_len) { struct tls_bio_mbuf_data* d; struct tls_mbuf* rd; int ret; ret = 0; if (likely(dst)) { #if OPENSSL_VERSION_NUMBER < 0x010100000L d = b->ptr; #else d = BIO_get_data(b); #endif BIO_clear_retry_flags(b); if (unlikely(d == 0 || d->rd->buf == 0)) { if (d == 0) BUG("tls_BIO_mbuf %p: read called with null b->ptr\n", b); else { /* this form of calling read with a null buffer is used as a shortcut when no data is available => simulate EAGIAN/WANT_READ */ TLS_BIO_DBG("read (%p, %p, %d) called with null read buffer" "(%p->%p) => simulating EAGAIN/WANT_READ\n", b, dst, dst_len, d, d->rd); BIO_set_retry_read(b); } return -1; } rd = d->rd; if (unlikely(rd->used == rd->pos && dst_len)) { /* mimic non-blocking read behaviour */ TLS_BIO_DBG("read (%p, %p, %d) called with full rd (%d)" " => simulating EAGAIN/WANT_READ\n", b, dst, dst_len, rd->used); BIO_set_retry_read(b); return -1; } ret = MIN_int(rd->used - rd->pos, dst_len); /* copy data from rd.buf into dst */ memcpy(dst, rd->buf+rd->pos, ret); TLS_BIO_DBG("read(%p, %p, %d) called with rd=%p pos=%d => %d bytes\n", b, dst, dst_len, rd->buf, rd->pos, ret); rd->pos += ret; /* if (unlikely(rd->pos < rd->used)) BIO_set_retry_read(b); */ } return ret; }
static long tls_bio_mbuf_ctrl(BIO* b, int cmd, long arg1, void* arg2) { long ret; ret=0; switch(cmd) { case BIO_C_SET_FD: case BIO_C_GET_FD: ret = -1; /* error, not supported */ break; case BIO_CTRL_GET_CLOSE: case BIO_CTRL_SET_CLOSE: ret = 0; break; case BIO_CTRL_DUP: case BIO_CTRL_FLUSH: ret = 1; break; case BIO_CTRL_RESET: case BIO_C_FILE_SEEK: case BIO_C_FILE_TELL: case BIO_CTRL_INFO: case BIO_CTRL_PENDING: case BIO_CTRL_WPENDING: default: ret = 0; break; } TLS_BIO_DBG("ctrl called (%p, %d, %ld, %p) => %ld\n", b, cmd, arg1, arg2, ret); return ret; }
/** create a new BIO. * (internal openssl use via the tls_mbuf method) * @return 1 on success, 0 on error. */ static int tls_bio_mbuf_new(BIO* b) { struct tls_bio_mbuf_data* d; TLS_BIO_DBG("tls_bio_mbuf_new called (%p)\n", b); #if OPENSSL_VERSION_NUMBER < 0x010100000L b->init = 0; /* not initialized yet */ b->num = 0; b->ptr = 0; b->flags = 0; d = OPENSSL_malloc(sizeof(*d)); if (unlikely(d == 0)) return 0; d->rd = 0; d->wr = 0; b->ptr = d; #else BIO_set_init(b, 0); BIO_set_data(b, NULL); d = OPENSSL_zalloc(sizeof(*d)); if (unlikely(d == 0)) return 0; BIO_set_data(b, d); #endif return 1; }
static int tls_bio_mbuf_puts(BIO* b, const char* s) { int len; TLS_BIO_DBG("puts called (%p, %s)\n", b, s); len=strlen(s); return tls_bio_mbuf_write(b, s, len); }
/** write to a mbuf. * (internal openssl use via the tls_mbuf method) * @return bytes written on success (0<= ret <=src_len), -1 on error or buffer * full (in this case sets should_retry_write). */ static int tls_bio_mbuf_write(BIO* b, const char* src, int src_len) { struct tls_bio_mbuf_data* d; struct tls_mbuf* wr; int ret; ret = 0; #if OPENSSL_VERSION_NUMBER < 0x010100000L d = b->ptr; #else d = BIO_get_data(b); #endif BIO_clear_retry_flags(b); if (unlikely(d == 0 || d->wr->buf == 0)) { if (d == 0) BUG("tls_BIO_mbuf %p: write called with null b->ptr\n", b); else { /* this form of calling write with a null buffer is used as a shortcut when no data is available => simulate EAGAIN/WANT_WRITE */ TLS_BIO_DBG("write (%p, %p, %d) called with null buffer" " => simulating WANT_WRITE\n", b, src, src_len); BIO_set_retry_write(b); } return -1; } wr = d->wr; if (unlikely(wr->size == wr->used && src_len)) { /* mimic non-blocking socket behaviour */ TLS_BIO_DBG("write (%p, %p, %d) called with full wr buffer (%d)" " => simulating WANT_WRITE\n", b, src, src_len, wr->used); BIO_set_retry_write(b); return -1; } ret = MIN_int(wr->size - wr->used, src_len); memcpy(wr->buf + wr->used, src, ret); wr->used += ret; /* if (unlikely(ret < src_len)) BIO_set_retry_write(); */ TLS_BIO_DBG("write called (%p, %p, %d) => %d\n", b, src, src_len, ret); return ret; }
/** destroy a tls mbuf BIO. * (internal openssl use via the tls_mbuf method) * @return 1 on success, 0 on error. */ static int tls_bio_mbuf_free(BIO* b) { TLS_BIO_DBG("tls_bio_mbuf_free called (%p)\n", b); if (unlikely( b == 0)) return 0; if (likely(b->ptr)){ OPENSSL_free(b->ptr); b->ptr = 0; b->init = 0; } return 1; }
/** create an initialize a new tls_BIO_mbuf. * @return new BIO on success (!=0), 0 on error. */ BIO* tls_BIO_new_mbuf(struct tls_mbuf* rd, struct tls_mbuf* wr) { BIO* ret; TLS_BIO_DBG("tls_BIO_new_mbuf called (%p, %p)\n", rd, wr); ret = BIO_new(tls_BIO_mbuf()); if (unlikely(ret == 0)) return 0; if (unlikely(tls_BIO_mbuf_set(ret, rd, wr) == 0)) { BIO_free(ret); return 0; } return ret; }
/** sets the read and write mbuf for an mbuf BIO. * @return 1 on success, 0 on error (openssl BIO convention). */ int tls_BIO_mbuf_set(BIO* b, struct tls_mbuf* rd, struct tls_mbuf* wr) { struct tls_bio_mbuf_data* d; TLS_BIO_DBG("tls_BIO_mbuf_set called (%p => %p, %p)\n", b, rd, wr); if (unlikely(b->ptr == 0)){ BUG("null BIO ptr\n"); return 0; } d = b->ptr; d->rd = rd; d->wr = wr; b->init = 1; return 1; }
/** create a new BIO. * (internal openssl use via the tls_mbuf method) * @return 1 on success, 0 on error. */ static int tls_bio_mbuf_new(BIO* b) { struct tls_bio_mbuf_data* d; TLS_BIO_DBG("tls_bio_mbuf_new called (%p)\n", b); b->init = 0; /* not initialized yet */ b->num = 0; b->ptr = 0; b->flags = 0; d = OPENSSL_malloc(sizeof(*d)); if (unlikely(d == 0)) return 0; d->rd = 0; d->wr = 0; b->ptr = d; return 1; }
/** sets the read and write mbuf for an mbuf BIO. * @return 1 on success, 0 on error (openssl BIO convention). */ int tls_BIO_mbuf_set(BIO* b, struct tls_mbuf* rd, struct tls_mbuf* wr) { struct tls_bio_mbuf_data* d; TLS_BIO_DBG("tls_BIO_mbuf_set called (%p => %p, %p)\n", b, rd, wr); #if OPENSSL_VERSION_NUMBER < 0x010100000L d = b->ptr; #else d = BIO_get_data(b); #endif if (unlikely(d == 0)){ BUG("null BIO ptr data\n"); return 0; } d->rd = rd; d->wr = wr; #if OPENSSL_VERSION_NUMBER < 0x010100000L b->init = 1; #else BIO_set_init(b, 1); #endif return 1; }
/** destroy a tls mbuf BIO. * (internal openssl use via the tls_mbuf method) * @return 1 on success, 0 on error. */ static int tls_bio_mbuf_free(BIO* b) { TLS_BIO_DBG("tls_bio_mbuf_free called (%p)\n", b); if (unlikely( b == 0)) return 0; #if OPENSSL_VERSION_NUMBER < 0x010100000L if (likely(b->ptr)){ OPENSSL_free(b->ptr); b->ptr = 0; b->init = 0; } #else do { struct tls_bio_mbuf_data* d; d = BIO_get_data(b); if (likely(d)) { OPENSSL_free(d); BIO_set_data(b, NULL); BIO_set_init(b, 0); } } while(0); #endif return 1; }