Home | History | Annotate | Download | only in streams
      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.
     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 
     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)
     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 
     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 
     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 
     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