/src/pdns/pdns/dnsdistdist/channel.cc
Line | Count | Source (jump to first uncovered line) |
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 | | |
25 | | namespace pdns::channel |
26 | | { |
27 | | |
28 | | Notifier::Notifier(FDWrapper&& descriptor) : |
29 | | d_fd(std::move(descriptor)) |
30 | 0 | { |
31 | 0 | } |
32 | | |
33 | | bool Notifier::notify() const |
34 | 0 | { |
35 | 0 | char data = 'a'; |
36 | 0 | while (true) { |
37 | 0 | auto sent = write(d_fd.getHandle(), &data, sizeof(data)); |
38 | 0 | if (sent == 0) { |
39 | 0 | throw std::runtime_error("Unable to write to channel notifier pipe: remote end has been closed"); |
40 | 0 | } |
41 | 0 | if (sent != sizeof(data)) { |
42 | 0 | if (errno == EINTR) { |
43 | 0 | continue; |
44 | 0 | } |
45 | 0 | if (errno == EAGAIN || errno == EWOULDBLOCK) { |
46 | 0 | return false; |
47 | 0 | } |
48 | 0 | throw std::runtime_error("Unable to write to channel notifier pipe: " + stringerror()); |
49 | 0 | } |
50 | 0 | return true; |
51 | 0 | } |
52 | 0 | } |
53 | | |
54 | | Waiter::Waiter(FDWrapper&& descriptor, bool throwOnEOF) : |
55 | | d_fd(std::move(descriptor)), d_throwOnEOF(throwOnEOF) |
56 | 0 | { |
57 | 0 | } |
58 | | |
59 | | void Waiter::clear() |
60 | 0 | { |
61 | 0 | ssize_t got{0}; |
62 | 0 | do { |
63 | 0 | char data{0}; |
64 | 0 | got = read(d_fd.getHandle(), &data, sizeof(data)); |
65 | 0 | if (got == 0) { |
66 | 0 | d_closed = true; |
67 | 0 | if (!d_throwOnEOF) { |
68 | 0 | return; |
69 | 0 | } |
70 | 0 | throw std::runtime_error("EOF while clearing channel notifier pipe"); |
71 | 0 | } |
72 | 0 | if (got == -1) { |
73 | 0 | if (errno == EINTR) { |
74 | 0 | continue; |
75 | 0 | } |
76 | 0 | if (errno == EAGAIN || errno == EWOULDBLOCK) { |
77 | 0 | break; |
78 | 0 | } |
79 | 0 | throw std::runtime_error("Error while clearing channel notifier pipe: " + stringerror()); |
80 | 0 | } |
81 | 0 | } while (got > 0); |
82 | 0 | } |
83 | | |
84 | | int Waiter::getDescriptor() const |
85 | 0 | { |
86 | 0 | return d_fd.getHandle(); |
87 | 0 | } |
88 | | |
89 | | std::pair<Notifier, Waiter> createNotificationQueue(bool nonBlocking, size_t pipeBufferSize, bool throwOnEOF) |
90 | 0 | { |
91 | 0 | std::array<int, 2> fds = {-1, -1}; |
92 | 0 | if (pipe(fds.data()) < 0) { |
93 | 0 | throw std::runtime_error("Error creating notification channel pipe: " + stringerror()); |
94 | 0 | } |
95 | | |
96 | 0 | FDWrapper sender(fds[1]); |
97 | 0 | FDWrapper receiver(fds[0]); |
98 | |
|
99 | 0 | if (nonBlocking && !setNonBlocking(receiver.getHandle())) { |
100 | 0 | int err = errno; |
101 | 0 | throw std::runtime_error("Error making notification channel pipe non-blocking: " + stringerror(err)); |
102 | 0 | } |
103 | | |
104 | 0 | if (nonBlocking && !setNonBlocking(sender.getHandle())) { |
105 | 0 | int err = errno; |
106 | 0 | throw std::runtime_error("Error making notification channel pipe non-blocking: " + stringerror(err)); |
107 | 0 | } |
108 | | |
109 | 0 | if (pipeBufferSize > 0 && getPipeBufferSize(receiver.getHandle()) < pipeBufferSize) { |
110 | 0 | setPipeBufferSize(receiver.getHandle(), pipeBufferSize); |
111 | 0 | } |
112 | |
|
113 | 0 | return {Notifier(std::move(sender)), Waiter(std::move(receiver), throwOnEOF)}; |
114 | 0 | } |
115 | | } |