int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read) { struct bio_bio_st* b; struct bio_bio_st* peer_b; size_t max_available; size_t dummy_read_offset; uint8_t* dummy_read_buf; assert(BIO_get_retry_flags(bio) == 0); if (!bio->init) { OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); return 0; } b = bio->ptr; if (!b || !b->peer) { OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); return 0; } peer_b = b->peer->ptr; if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); return 0; } if (!peer_b->zero_copy_read_lock) { OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); return 0; } max_available = bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset); if (bytes_read > max_available) { OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); return 0; } peer_b->len -= bytes_read; assert(peer_b->len >= 0); assert(peer_b->offset + bytes_read <= peer_b->size); /* Move read offset. If zero_copy_write_lock == 1 we must advance the * offset even if buffer becomes empty, to make sure * write_offset = (offset + len) mod size does not change. */ if (peer_b->offset + bytes_read == peer_b->size || (!peer_b->zero_copy_write_lock && peer_b->len == 0)) { peer_b->offset = 0; } else { peer_b->offset += bytes_read; } bio->num_read += bytes_read; peer_b->zero_copy_read_lock = 0; return 1; }
int BIO_zero_copy_get_read_buf(BIO* bio, uint8_t** out_read_buf, size_t* out_buf_offset, size_t* out_available_bytes) { struct bio_bio_st* b; struct bio_bio_st* peer_b; size_t max_available; *out_available_bytes = 0; BIO_clear_retry_flags(bio); if (!bio->init) { OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf, BIO_R_UNINITIALIZED); return 0; } b = bio->ptr; if (!b || !b->peer) { OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf, BIO_R_UNSUPPORTED_METHOD); return 0; } peer_b = b->peer->ptr; if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf, BIO_R_UNSUPPORTED_METHOD); return 0; } if (peer_b->zero_copy_read_lock) { OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf, BIO_R_INVALID_ARGUMENT); return 0; } peer_b->request = 0; /* Is not used by zero-copy API. */ max_available = bio_zero_copy_get_read_buf(peer_b, out_read_buf, out_buf_offset); assert(peer_b->buf != NULL); if (max_available > 0) { peer_b->zero_copy_read_lock = 1; } *out_available_bytes = max_available; return 1; }