blob: 7983f7b215197a67f2df6e574d5ef39bd628c0c7 [file] [log] [blame]
James Kuszmaul3224b8e2022-01-07 19:00:39 -08001#include "aos/util/scoped_pipe.h"
2
Stephan Pleinesb1177672024-05-27 17:48:32 -07003#include <errno.h>
James Kuszmaul3224b8e2022-01-07 19:00:39 -08004#include <fcntl.h>
Stephan Pleinesb1177672024-05-27 17:48:32 -07005#include <unistd.h>
6
7#include <ostream>
Austin Schuh60e77942022-05-16 17:48:24 -07008
Austin Schuh99f7c6a2024-06-25 22:07:44 -07009#include "absl/log/check.h"
10#include "absl/log/log.h"
James Kuszmaul3224b8e2022-01-07 19:00:39 -080011
12namespace aos::util {
13
14ScopedPipe::ScopedPipe(int fd) : fd_(fd) {}
15
16ScopedPipe::~ScopedPipe() {
17 if (fd_ != -1) {
18 PCHECK(close(fd_) != -1);
19 }
20}
21
22ScopedPipe::ScopedPipe(ScopedPipe &&scoped_pipe) : fd_(scoped_pipe.fd_) {
23 scoped_pipe.fd_ = -1;
24}
25
26ScopedPipe &ScopedPipe::operator=(ScopedPipe &&scoped_pipe) {
27 if (fd_ != -1) {
28 PCHECK(close(fd_) != -1);
29 }
30 fd_ = scoped_pipe.fd_;
31 scoped_pipe.fd_ = -1;
32 return *this;
33}
34
James Kuszmauld42edb42022-01-07 18:00:16 -080035ScopedPipe::PipePair ScopedPipe::MakePipe() {
James Kuszmaul3224b8e2022-01-07 19:00:39 -080036 int fds[2];
37 PCHECK(pipe(fds) != -1);
38 PCHECK(fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK) != -1);
39 PCHECK(fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | O_NONBLOCK) != -1);
James Kuszmauld42edb42022-01-07 18:00:16 -080040 return {std::unique_ptr<ScopedReadPipe>(new ScopedReadPipe(fds[0])),
41 std::unique_ptr<ScopedWritePipe>(new ScopedWritePipe(fds[1]))};
42}
43
44void ScopedPipe::SetCloexec() {
45 // FD_CLOEXEC is the only known file descriptor flag, but call GETFD just in
46 // case.
47 int flags = fcntl(fd(), F_GETFD);
48 PCHECK(flags != -1);
49 PCHECK(fcntl(fd(), F_SETFD, flags | FD_CLOEXEC) != -1);
James Kuszmaul3224b8e2022-01-07 19:00:39 -080050}
51
James Kuszmaul731a05d2022-01-07 17:59:26 -080052size_t ScopedPipe::ScopedReadPipe::Read(std::string *buffer) {
Austin Schuh6bdcc372024-06-27 14:49:11 -070053 CHECK(buffer != nullptr);
James Kuszmaul731a05d2022-01-07 17:59:26 -080054 constexpr ssize_t kBufferSize = 1024;
55 const size_t original_size = buffer->size();
56 size_t read_bytes = 0;
57 while (true) {
58 buffer->resize(buffer->size() + kBufferSize);
59 const ssize_t result =
60 read(fd(), buffer->data() + buffer->size() - kBufferSize, kBufferSize);
61 if (result == -1) {
62 if (errno == EAGAIN || errno == EWOULDBLOCK) {
Austin Schuh0d164112023-08-17 12:50:51 -070063 buffer->resize(original_size + read_bytes);
64 return read_bytes;
James Kuszmaul731a05d2022-01-07 17:59:26 -080065 }
66 PLOG(FATAL) << "Error on reading pipe.";
67 } else if (result < kBufferSize) {
68 read_bytes += result;
69 buffer->resize(original_size + read_bytes);
70 break;
71 } else {
72 CHECK_EQ(result, kBufferSize);
73 read_bytes += result;
74 }
75 }
76 return read_bytes;
77}
78
James Kuszmaul3224b8e2022-01-07 19:00:39 -080079std::optional<uint32_t> ScopedPipe::ScopedReadPipe::Read() {
80 uint32_t buf;
81 ssize_t result = read(fd(), &buf, sizeof(buf));
82 if (result == sizeof(buf)) {
83 return buf;
84 } else {
85 return std::nullopt;
86 }
87}
88
89void ScopedPipe::ScopedWritePipe::Write(uint32_t data) {
90 ssize_t result = write(fd(), &data, sizeof(data));
91 PCHECK(result != -1);
James Kuszmaul731a05d2022-01-07 17:59:26 -080092 CHECK_EQ(static_cast<size_t>(result), sizeof(data));
93}
94
95void ScopedPipe::ScopedWritePipe::Write(absl::Span<const uint8_t> data) {
96 ssize_t result = write(fd(), data.data(), data.size());
97 PCHECK(result != -1);
98 CHECK_EQ(static_cast<size_t>(result), data.size());
James Kuszmaul3224b8e2022-01-07 19:00:39 -080099}
100
101} // namespace aos::util