Coverage Report

Created: 2023-09-25 06:58

/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
}