mirror of https://github.com/bitcoin/bitcoin
parent
2e8116149c
commit
612f746a8f
@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2021 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#include <util/tokenpipe.h>
|
||||
|
||||
#include <config/bitcoin-config.h>
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
TokenPipeEnd TokenPipe::TakeReadEnd()
|
||||
{
|
||||
TokenPipeEnd res(m_fds[0]);
|
||||
m_fds[0] = -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
TokenPipeEnd TokenPipe::TakeWriteEnd()
|
||||
{
|
||||
TokenPipeEnd res(m_fds[1]);
|
||||
m_fds[1] = -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
TokenPipeEnd::TokenPipeEnd(int fd) : m_fd(fd)
|
||||
{
|
||||
}
|
||||
|
||||
TokenPipeEnd::~TokenPipeEnd()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
int TokenPipeEnd::TokenWrite(uint8_t token)
|
||||
{
|
||||
while (true) {
|
||||
ssize_t result = write(m_fd, &token, 1);
|
||||
if (result < 0) {
|
||||
// Failure. It's possible that the write was interrupted by a signal,
|
||||
// in that case retry.
|
||||
if (errno != EINTR) {
|
||||
return TS_ERR;
|
||||
}
|
||||
} else if (result == 0) {
|
||||
return TS_EOS;
|
||||
} else { // ==1
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int TokenPipeEnd::TokenRead()
|
||||
{
|
||||
uint8_t token;
|
||||
while (true) {
|
||||
ssize_t result = read(m_fd, &token, 1);
|
||||
if (result < 0) {
|
||||
// Failure. Check if the read was interrupted by a signal,
|
||||
// in that case retry.
|
||||
if (errno != EINTR) {
|
||||
return TS_ERR;
|
||||
}
|
||||
} else if (result == 0) {
|
||||
return TS_EOS;
|
||||
} else { // ==1
|
||||
return token;
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
void TokenPipeEnd::Close()
|
||||
{
|
||||
if (m_fd != -1) close(m_fd);
|
||||
m_fd = -1;
|
||||
}
|
||||
|
||||
std::optional<TokenPipe> TokenPipe::Make()
|
||||
{
|
||||
int fds[2] = {-1, -1};
|
||||
#if HAVE_O_CLOEXEC && HAVE_DECL_PIPE2
|
||||
if (pipe2(fds, O_CLOEXEC) != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
#else
|
||||
if (pipe(fds) != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif
|
||||
return TokenPipe(fds);
|
||||
}
|
||||
|
||||
TokenPipe::~TokenPipe()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void TokenPipe::Close()
|
||||
{
|
||||
if (m_fds[0] != -1) close(m_fds[0]);
|
||||
if (m_fds[1] != -1) close(m_fds[1]);
|
||||
m_fds[0] = m_fds[1] = -1;
|
||||
}
|
||||
|
||||
#endif // WIN32
|
@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2021 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_UTIL_TOKENPIPE_H
|
||||
#define BITCOIN_UTIL_TOKENPIPE_H
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
/** One end of a token pipe. */
|
||||
class TokenPipeEnd
|
||||
{
|
||||
private:
|
||||
int m_fd = -1;
|
||||
|
||||
public:
|
||||
TokenPipeEnd(int fd = -1);
|
||||
~TokenPipeEnd();
|
||||
|
||||
/** Return value constants for TokenWrite and TokenRead. */
|
||||
enum Status {
|
||||
TS_ERR = -1, //!< I/O error
|
||||
TS_EOS = -2, //!< Unexpected end of stream
|
||||
};
|
||||
|
||||
/** Write token to endpoint.
|
||||
*
|
||||
* @returns 0 If successful.
|
||||
* <0 if error:
|
||||
* TS_ERR If an error happened.
|
||||
* TS_EOS If end of stream happened.
|
||||
*/
|
||||
int TokenWrite(uint8_t token);
|
||||
|
||||
/** Read token from endpoint.
|
||||
*
|
||||
* @returns >=0 Token value, if successful.
|
||||
* <0 if error:
|
||||
* TS_ERR If an error happened.
|
||||
* TS_EOS If end of stream happened.
|
||||
*/
|
||||
int TokenRead();
|
||||
|
||||
/** Explicit close function.
|
||||
*/
|
||||
void Close();
|
||||
|
||||
/** Return whether endpoint is open.
|
||||
*/
|
||||
bool IsOpen() { return m_fd != -1; }
|
||||
|
||||
// Move-only class.
|
||||
TokenPipeEnd(TokenPipeEnd&& other)
|
||||
{
|
||||
m_fd = other.m_fd;
|
||||
other.m_fd = -1;
|
||||
}
|
||||
TokenPipeEnd& operator=(TokenPipeEnd&& other)
|
||||
{
|
||||
Close();
|
||||
m_fd = other.m_fd;
|
||||
other.m_fd = -1;
|
||||
return *this;
|
||||
}
|
||||
TokenPipeEnd(const TokenPipeEnd&) = delete;
|
||||
TokenPipeEnd& operator=(const TokenPipeEnd&) = delete;
|
||||
};
|
||||
|
||||
/** An interprocess or interthread pipe for sending tokens (one-byte values)
|
||||
* over.
|
||||
*/
|
||||
class TokenPipe
|
||||
{
|
||||
private:
|
||||
int m_fds[2] = {-1, -1};
|
||||
|
||||
TokenPipe(int fds[2]) : m_fds{fds[0], fds[1]} {}
|
||||
|
||||
public:
|
||||
~TokenPipe();
|
||||
|
||||
/** Create a new pipe.
|
||||
* @returns The created TokenPipe, or an empty std::nullopt in case of error.
|
||||
*/
|
||||
static std::optional<TokenPipe> Make();
|
||||
|
||||
/** Take the read end of this pipe. This can only be called once,
|
||||
* as the object will be moved out.
|
||||
*/
|
||||
TokenPipeEnd TakeReadEnd();
|
||||
|
||||
/** Take the write end of this pipe. This should only be called once,
|
||||
* as the object will be moved out.
|
||||
*/
|
||||
TokenPipeEnd TakeWriteEnd();
|
||||
|
||||
/** Close and end of the pipe that hasn't been moved out.
|
||||
*/
|
||||
void Close();
|
||||
|
||||
// Move-only class.
|
||||
TokenPipe(TokenPipe&& other)
|
||||
{
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
m_fds[i] = other.m_fds[i];
|
||||
other.m_fds[i] = -1;
|
||||
}
|
||||
}
|
||||
TokenPipe& operator=(TokenPipe&& other)
|
||||
{
|
||||
Close();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
m_fds[i] = other.m_fds[i];
|
||||
other.m_fds[i] = -1;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
TokenPipe(const TokenPipe&) = delete;
|
||||
TokenPipe& operator=(const TokenPipe&) = delete;
|
||||
};
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
#endif // BITCOIN_UTIL_TOKENPIPE_H
|
Loading…
Reference in new issue