]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/channel.cc
Merge pull request #14020 from omoerbeek/rec-compiling-rust-dcos
[thirdparty/pdns.git] / pdns / channel.cc
CommitLineData
7f98f4ba
RG
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include "channel.hh"
24
35b27ac8 25namespace pdns::channel
7f98f4ba
RG
26{
27
98769adc
RG
28Notifier::Notifier(FDWrapper&& descriptor) :
29 d_fd(std::move(descriptor))
bf70d526
RG
30{
31}
7f98f4ba 32
bf70d526
RG
33bool Notifier::notify() const
34{
35 char data = 'a';
36 while (true) {
37 auto sent = write(d_fd.getHandle(), &data, sizeof(data));
38 if (sent == 0) {
39 throw std::runtime_error("Unable to write to channel notifier pipe: remote end has been closed");
40 }
41 if (sent != sizeof(data)) {
42 if (errno == EINTR) {
43 continue;
43ec3a21 44 }
bf70d526
RG
45 if (errno == EAGAIN || errno == EWOULDBLOCK) {
46 return false;
7f98f4ba 47 }
bf70d526 48 throw std::runtime_error("Unable to write to channel notifier pipe: " + stringerror());
7f98f4ba 49 }
bf70d526 50 return true;
7f98f4ba 51 }
bf70d526 52}
7f98f4ba 53
98769adc
RG
54Waiter::Waiter(FDWrapper&& descriptor, bool throwOnEOF) :
55 d_fd(std::move(descriptor)), d_throwOnEOF(throwOnEOF)
bf70d526
RG
56{
57}
7f98f4ba 58
bf70d526
RG
59void Waiter::clear()
60{
61 ssize_t got{0};
62 do {
63 char data{0};
64 got = read(d_fd.getHandle(), &data, sizeof(data));
65 if (got == 0) {
66 d_closed = true;
67 if (!d_throwOnEOF) {
68 return;
7f98f4ba 69 }
bf70d526
RG
70 throw std::runtime_error("EOF while clearing channel notifier pipe");
71 }
72 if (got == -1) {
73 if (errno == EINTR) {
74 continue;
7f98f4ba 75 }
bf70d526
RG
76 if (errno == EAGAIN || errno == EWOULDBLOCK) {
77 break;
78 }
79 throw std::runtime_error("Error while clearing channel notifier pipe: " + stringerror());
7f98f4ba 80 }
bf70d526
RG
81 } while (got > 0);
82}
7f98f4ba 83
bf70d526
RG
84int Waiter::getDescriptor() const
85{
86 return d_fd.getHandle();
87}
7f98f4ba 88
bf70d526
RG
89std::pair<Notifier, Waiter> createNotificationQueue(bool nonBlocking, size_t pipeBufferSize, bool throwOnEOF)
90{
91 std::array<int, 2> fds = {-1, -1};
92 if (pipe(fds.data()) < 0) {
93 throw std::runtime_error("Error creating notification channel pipe: " + stringerror());
94 }
7f98f4ba 95
bf70d526
RG
96 FDWrapper sender(fds[1]);
97 FDWrapper receiver(fds[0]);
7f98f4ba 98
bf70d526
RG
99 if (nonBlocking && !setNonBlocking(receiver.getHandle())) {
100 int err = errno;
101 throw std::runtime_error("Error making notification channel pipe non-blocking: " + stringerror(err));
102 }
7f98f4ba 103
bf70d526
RG
104 if (nonBlocking && !setNonBlocking(sender.getHandle())) {
105 int err = errno;
106 throw std::runtime_error("Error making notification channel pipe non-blocking: " + stringerror(err));
7f98f4ba 107 }
bf70d526
RG
108
109 if (pipeBufferSize > 0 && getPipeBufferSize(receiver.getHandle()) < pipeBufferSize) {
110 setPipeBufferSize(receiver.getHandle(), pipeBufferSize);
111 }
112
ebd45ede 113 return {Notifier(std::move(sender)), Waiter(std::move(receiver), throwOnEOF)};
bf70d526 114}
7f98f4ba 115}