tokenpipe.cpp raw

   1  // Copyright (c) 2021-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <bitcoin-build-config.h> // IWYU pragma: keep
   6  
   7  #include <util/tokenpipe.h>
   8  
   9  #ifndef WIN32
  10  
  11  #include <cerrno>
  12  #include <optional>
  13  
  14  #include <fcntl.h>
  15  #include <sys/types.h>
  16  #include <unistd.h>
  17  
  18  TokenPipeEnd TokenPipe::TakeReadEnd()
  19  {
  20      TokenPipeEnd res(m_fds[0]);
  21      m_fds[0] = -1;
  22      return res;
  23  }
  24  
  25  TokenPipeEnd TokenPipe::TakeWriteEnd()
  26  {
  27      TokenPipeEnd res(m_fds[1]);
  28      m_fds[1] = -1;
  29      return res;
  30  }
  31  
  32  TokenPipeEnd::TokenPipeEnd(int fd) : m_fd(fd)
  33  {
  34  }
  35  
  36  TokenPipeEnd::~TokenPipeEnd()
  37  {
  38      Close();
  39  }
  40  
  41  int TokenPipeEnd::TokenWrite(uint8_t token)
  42  {
  43      while (true) {
  44          ssize_t result = write(m_fd, &token, 1);
  45          if (result < 0) {
  46              // Failure. It's possible that the write was interrupted by a signal,
  47              // in that case retry.
  48              if (errno != EINTR) {
  49                  return TS_ERR;
  50              }
  51          } else if (result == 0) {
  52              return TS_EOS;
  53          } else { // ==1
  54              return 0;
  55          }
  56      }
  57  }
  58  
  59  int TokenPipeEnd::TokenRead()
  60  {
  61      uint8_t token;
  62      while (true) {
  63          ssize_t result = read(m_fd, &token, 1);
  64          if (result < 0) {
  65              // Failure. Check if the read was interrupted by a signal,
  66              // in that case retry.
  67              if (errno != EINTR) {
  68                  return TS_ERR;
  69              }
  70          } else if (result == 0) {
  71              return TS_EOS;
  72          } else { // ==1
  73              return token;
  74          }
  75      }
  76      return token;
  77  }
  78  
  79  void TokenPipeEnd::Close()
  80  {
  81      if (m_fd != -1) close(m_fd);
  82      m_fd = -1;
  83  }
  84  
  85  std::optional<TokenPipe> TokenPipe::Make()
  86  {
  87      int fds[2] = {-1, -1};
  88  #if HAVE_O_CLOEXEC && HAVE_DECL_PIPE2
  89      if (pipe2(fds, O_CLOEXEC) != 0) {
  90          return std::nullopt;
  91      }
  92  #else
  93      if (pipe(fds) != 0) {
  94          return std::nullopt;
  95      }
  96  #endif
  97      return TokenPipe(fds);
  98  }
  99  
 100  TokenPipe::~TokenPipe()
 101  {
 102      Close();
 103  }
 104  
 105  void TokenPipe::Close()
 106  {
 107      if (m_fds[0] != -1) close(m_fds[0]);
 108      if (m_fds[1] != -1) close(m_fds[1]);
 109      m_fds[0] = m_fds[1] = -1;
 110  }
 111  
 112  #endif // WIN32
 113