]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/pollmplexer.cc
Merge pull request #14020 from omoerbeek/rec-compiling-rust-dcos
[thirdparty/pdns.git] / pdns / pollmplexer.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include "mplexer.hh"
5 #include "sstuff.hh"
6 #include <iostream>
7 #include <poll.h>
8 #include <unordered_map>
9 #include "misc.hh"
10 #include "namespaces.hh"
11
12 FDMultiplexer* FDMultiplexer::getMultiplexerSilent(unsigned int maxEventsHint)
13 {
14 FDMultiplexer* ret = nullptr;
15 for (const auto& i : FDMultiplexer::getMultiplexerMap()) {
16 try {
17 ret = i.second(std::min(maxEventsHint, FDMultiplexer::s_maxevents));
18 return ret;
19 }
20 catch (const FDMultiplexerException& fe) {
21 }
22 catch (...) {
23 }
24 }
25 return ret;
26 }
27
28 class PollFDMultiplexer : public FDMultiplexer
29 {
30 public:
31 PollFDMultiplexer(unsigned int /* maxEventsHint */)
32 {}
33
34 int run(struct timeval* tv, int timeout = 500) override;
35 void getAvailableFDs(std::vector<int>& fds, int timeout) override;
36
37 void addFD(int fd, FDMultiplexer::EventKind) override;
38 void removeFD(int fd, FDMultiplexer::EventKind) override;
39
40 string getName() const override
41 {
42 return "poll";
43 }
44
45 private:
46 std::unordered_map<int, struct pollfd> d_pollfds;
47 vector<struct pollfd> preparePollFD() const;
48 };
49
50 static FDMultiplexer* make(unsigned int maxEventsHint)
51 {
52 return new PollFDMultiplexer(maxEventsHint);
53 }
54
55 static struct RegisterOurselves
56 {
57 RegisterOurselves()
58 {
59 FDMultiplexer::getMultiplexerMap().emplace(2, &make);
60 }
61 } doIt;
62
63 static int convertEventKind(FDMultiplexer::EventKind kind)
64 {
65 switch (kind) {
66 case FDMultiplexer::EventKind::Read:
67 return POLLIN;
68 case FDMultiplexer::EventKind::Write:
69 return POLLOUT;
70 case FDMultiplexer::EventKind::Both:
71 return POLLIN | POLLOUT;
72 }
73 throw std::runtime_error("Unhandled event kind in the ports multiplexer");
74 }
75
76 void PollFDMultiplexer::addFD(int fd, FDMultiplexer::EventKind kind)
77 {
78 if (d_pollfds.count(fd) == 0) {
79 auto& pollfd = d_pollfds[fd];
80 pollfd.fd = fd;
81 pollfd.events = 0;
82 }
83 auto& pollfd = d_pollfds.at(fd);
84 pollfd.events |= convertEventKind(kind);
85 }
86
87 void PollFDMultiplexer::removeFD(int fd, FDMultiplexer::EventKind)
88 {
89 d_pollfds.erase(fd);
90 }
91
92 vector<struct pollfd> PollFDMultiplexer::preparePollFD() const
93 {
94 std::vector<struct pollfd> result;
95 result.reserve(d_pollfds.size());
96 for (const auto& entry : d_pollfds) {
97 result.push_back(entry.second);
98 }
99
100 return result;
101 }
102
103 void PollFDMultiplexer::getAvailableFDs(std::vector<int>& fds, int timeout)
104 {
105 auto pollfds = preparePollFD();
106 if (pollfds.empty()) {
107 return;
108 }
109
110 int ret = poll(&pollfds[0], pollfds.size(), timeout);
111
112 if (ret < 0 && errno != EINTR) {
113 throw FDMultiplexerException("poll returned error: " + stringerror());
114 }
115
116 for (const auto& pollfd : pollfds) {
117 if (pollfd.revents & POLLIN || pollfd.revents & POLLOUT || pollfd.revents & POLLERR || pollfd.revents & POLLHUP) {
118 fds.push_back(pollfd.fd);
119 }
120 }
121 }
122
123 int PollFDMultiplexer::run(struct timeval* now, int timeout)
124 {
125 if (d_inrun) {
126 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
127 }
128
129 auto pollfds = preparePollFD();
130 if (pollfds.empty()) {
131 gettimeofday(now, nullptr); // MANDATORY!
132 return 0;
133 }
134
135 int ret = poll(&pollfds[0], pollfds.size(), timeout);
136 gettimeofday(now, nullptr); // MANDATORY!
137
138 if (ret < 0 && errno != EINTR) {
139 throw FDMultiplexerException("poll returned error: " + stringerror());
140 }
141
142 d_inrun = true;
143 int count = 0;
144 for (const auto& pollfd : pollfds) {
145 if (pollfd.revents & POLLIN || pollfd.revents & POLLERR || pollfd.revents & POLLHUP) {
146 const auto& iter = d_readCallbacks.find(pollfd.fd);
147 if (iter != d_readCallbacks.end()) {
148 iter->d_callback(iter->d_fd, iter->d_parameter);
149 count++;
150 }
151 }
152
153 if (pollfd.revents & POLLOUT || pollfd.revents & POLLERR) {
154 const auto& iter = d_writeCallbacks.find(pollfd.fd);
155 if (iter != d_writeCallbacks.end()) {
156 iter->d_callback(iter->d_fd, iter->d_parameter);
157 count++;
158 }
159 }
160 }
161
162 d_inrun = false;
163 return count;
164 }
165
166 #if 0
167
168 void acceptData(int fd, boost::any& parameter)
169 {
170 cout<<"Have data on fd "<<fd<<endl;
171 Socket* sock=boost::any_cast<Socket*>(parameter);
172 string packet;
173 IPEndpoint rem;
174 sock->recvFrom(packet, rem);
175 cout<<"Received "<<packet.size()<<" bytes!\n";
176 }
177
178
179 int main()
180 {
181 Socket s(AF_INET, SOCK_DGRAM);
182
183 IPEndpoint loc("0.0.0.0", 2000);
184 s.bind(loc);
185
186 PollFDMultiplexer sfm;
187
188 sfm.addReadFD(s.getHandle(), &acceptData, &s);
189
190 for(int n=0; n < 100 ; ++n) {
191 sfm.run();
192 }
193 sfm.removeReadFD(s.getHandle());
194 sfm.removeReadFD(s.getHandle());
195 }
196 #endif