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
12 namespace brillo {
13
14 namespace {
15
16 // Internal functions for implementing OpenSSL BIO on brillo::Stream.
stream_write(BIO * bio,const char * buf,int size)17 int 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
stream_read(BIO * bio,char * buf,int size)32 int 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)
stream_ctrl(BIO * bio,int cmd,long,void *)50 long 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
stream_new(BIO * bio)58 int 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
stream_free(BIO * bio)65 int 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.
77 BIO_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
BIO_new_stream(brillo::Stream * stream)92 BIO* 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