// Copyright 2015 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <brillo/streams/openssl_stream_bio.h> #include <openssl/bio.h> #include <base/numerics/safe_conversions.h> #include <brillo/streams/stream.h> namespace brillo { namespace { // Internal functions for implementing OpenSSL BIO on brillo::Stream. int stream_write(BIO* bio, const char* buf, int size) { brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr); size_t written = 0; BIO_clear_retry_flags(bio); if (!stream->WriteNonBlocking(buf, size, &written, nullptr)) return -1; if (written == 0) { // Socket's output buffer is full, try again later. BIO_set_retry_write(bio); return -1; } return base::checked_cast<int>(written); } int stream_read(BIO* bio, char* buf, int size) { brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr); size_t read = 0; BIO_clear_retry_flags(bio); bool eos = false; if (!stream->ReadNonBlocking(buf, size, &read, &eos, nullptr)) return -1; if (read == 0 && !eos) { // If no data is available on the socket and it is still not closed, // ask OpenSSL to try again later. BIO_set_retry_read(bio); return -1; } return base::checked_cast<int>(read); } // NOLINTNEXTLINE(runtime/int) long stream_ctrl(BIO* bio, int cmd, long /* num */, void* /* ptr */) { if (cmd == BIO_CTRL_FLUSH) { brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr); return stream->FlushBlocking(nullptr) ? 1 : 0; } return 0; } int stream_new(BIO* bio) { bio->shutdown = 0; // By default do not close underlying stream on shutdown. bio->init = 0; bio->num = -1; // not used. return 1; } int stream_free(BIO* bio) { if (!bio) return 0; if (bio->init) { bio->ptr = nullptr; bio->init = 0; } return 1; } // BIO_METHOD structure describing the BIO built on top of brillo::Stream. BIO_METHOD stream_method = { 0x7F | BIO_TYPE_SOURCE_SINK, // type: 0x7F is an arbitrary unused type ID. "stream", // name stream_write, // write function stream_read, // read function nullptr, // puts function, not implemented nullptr, // gets function, not implemented stream_ctrl, // control function stream_new, // creation stream_free, // free nullptr, // callback function, not used }; } // anonymous namespace BIO* BIO_new_stream(brillo::Stream* stream) { BIO* bio = BIO_new(&stream_method); if (bio) { bio->ptr = stream; bio->init = 1; } return bio; } } // namespace brillo