1// Copyright 2015 The Chromium OS Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <brillo/streams/openssl_stream_bio.h> 6 7#include <openssl/bio.h> 8 9#include <base/numerics/safe_conversions.h> 10#include <brillo/streams/stream.h> 11 12namespace brillo { 13 14namespace { 15 16// Internal functions for implementing OpenSSL BIO on brillo::Stream. 17int stream_write(BIO* bio, const char* buf, int size) { 18 brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr); 19 size_t written = 0; 20 BIO_clear_retry_flags(bio); 21 if (!stream->WriteNonBlocking(buf, size, &written, nullptr)) 22 return -1; 23 24 if (written == 0) { 25 // Socket's output buffer is full, try again later. 26 BIO_set_retry_write(bio); 27 return -1; 28 } 29 return base::checked_cast<int>(written); 30} 31 32int stream_read(BIO* bio, char* buf, int size) { 33 brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr); 34 size_t read = 0; 35 BIO_clear_retry_flags(bio); 36 bool eos = false; 37 if (!stream->ReadNonBlocking(buf, size, &read, &eos, nullptr)) 38 return -1; 39 40 if (read == 0 && !eos) { 41 // If no data is available on the socket and it is still not closed, 42 // ask OpenSSL to try again later. 43 BIO_set_retry_read(bio); 44 return -1; 45 } 46 return base::checked_cast<int>(read); 47} 48 49// NOLINTNEXTLINE(runtime/int) 50long stream_ctrl(BIO* bio, int cmd, long /* num */, void* /* ptr */) { 51 if (cmd == BIO_CTRL_FLUSH) { 52 brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr); 53 return stream->FlushBlocking(nullptr) ? 1 : 0; 54 } 55 return 0; 56} 57 58int stream_new(BIO* bio) { 59 bio->shutdown = 0; // By default do not close underlying stream on shutdown. 60 bio->init = 0; 61 bio->num = -1; // not used. 62 return 1; 63} 64 65int stream_free(BIO* bio) { 66 if (!bio) 67 return 0; 68 69 if (bio->init) { 70 bio->ptr = nullptr; 71 bio->init = 0; 72 } 73 return 1; 74} 75 76// BIO_METHOD structure describing the BIO built on top of brillo::Stream. 77BIO_METHOD stream_method = { 78 0x7F | BIO_TYPE_SOURCE_SINK, // type: 0x7F is an arbitrary unused type ID. 79 "stream", // name 80 stream_write, // write function 81 stream_read, // read function 82 nullptr, // puts function, not implemented 83 nullptr, // gets function, not implemented 84 stream_ctrl, // control function 85 stream_new, // creation 86 stream_free, // free 87 nullptr, // callback function, not used 88}; 89 90} // anonymous namespace 91 92BIO* BIO_new_stream(brillo::Stream* stream) { 93 BIO* bio = BIO_new(&stream_method); 94 if (bio) { 95 bio->ptr = stream; 96 bio->init = 1; 97 } 98 return bio; 99} 100 101} // namespace brillo 102