• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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