| // 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 |