You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
3.8 KiB
153 lines
3.8 KiB
// 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 {
|
|
|
|
// TODO(crbug.com/984789): Remove once support for OpenSSL <1.1 is dropped.
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
static void BIO_set_data(BIO* a, void* ptr) {
|
|
a->ptr = ptr;
|
|
}
|
|
|
|
static void* BIO_get_data(BIO* a) {
|
|
return a->ptr;
|
|
}
|
|
|
|
static void BIO_set_init(BIO* a, int init) {
|
|
a->init = init;
|
|
}
|
|
|
|
static int BIO_get_init(BIO* a) {
|
|
return a->init;
|
|
}
|
|
|
|
static void BIO_set_shutdown(BIO* a, int shut) {
|
|
a->shutdown = shut;
|
|
}
|
|
#endif
|
|
|
|
// 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_get_data(bio));
|
|
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_get_data(bio));
|
|
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_get_data(bio));
|
|
return stream->FlushBlocking(nullptr) ? 1 : 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int stream_new(BIO* bio) {
|
|
// By default do not close underlying stream on shutdown.
|
|
BIO_set_shutdown(bio, 0);
|
|
BIO_set_init(bio, 0);
|
|
return 1;
|
|
}
|
|
|
|
int stream_free(BIO* bio) {
|
|
if (!bio)
|
|
return 0;
|
|
|
|
if (BIO_get_init(bio)) {
|
|
BIO_set_data(bio, nullptr);
|
|
BIO_set_init(bio, 0);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
// TODO(crbug.com/984789): Remove #ifdef once support for OpenSSL <1.1 is
|
|
// dropped.
|
|
|
|
// 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
|
|
};
|
|
|
|
BIO_METHOD* stream_get_method() {
|
|
return &stream_method;
|
|
}
|
|
|
|
#else
|
|
|
|
BIO_METHOD* stream_get_method() {
|
|
static BIO_METHOD* stream_method;
|
|
|
|
if (!stream_method) {
|
|
stream_method = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK,
|
|
"stream");
|
|
BIO_meth_set_write(stream_method, stream_write);
|
|
BIO_meth_set_read(stream_method, stream_read);
|
|
BIO_meth_set_ctrl(stream_method, stream_ctrl);
|
|
BIO_meth_set_create(stream_method, stream_new);
|
|
BIO_meth_set_destroy(stream_method, stream_free);
|
|
}
|
|
|
|
return stream_method;
|
|
}
|
|
|
|
#endif
|
|
|
|
} // anonymous namespace
|
|
|
|
BIO* BIO_new_stream(brillo::Stream* stream) {
|
|
BIO* bio = BIO_new(stream_get_method());
|
|
if (bio) {
|
|
BIO_set_data(bio, stream);
|
|
BIO_set_init(bio, 1);
|
|
}
|
|
return bio;
|
|
}
|
|
|
|
} // namespace brillo
|