]>
Commit | Line | Data |
---|---|---|
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 | 25 | namespace pdns::channel |
7f98f4ba RG |
26 | { |
27 | ||
98769adc RG |
28 | Notifier::Notifier(FDWrapper&& descriptor) : |
29 | d_fd(std::move(descriptor)) | |
bf70d526 RG |
30 | { |
31 | } | |
7f98f4ba | 32 | |
bf70d526 RG |
33 | bool 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 |
54 | Waiter::Waiter(FDWrapper&& descriptor, bool throwOnEOF) : |
55 | d_fd(std::move(descriptor)), d_throwOnEOF(throwOnEOF) | |
bf70d526 RG |
56 | { |
57 | } | |
7f98f4ba | 58 | |
bf70d526 RG |
59 | void 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 |
84 | int Waiter::getDescriptor() const |
85 | { | |
86 | return d_fd.getHandle(); | |
87 | } | |
7f98f4ba | 88 | |
bf70d526 RG |
89 | std::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 | } |