]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/devpollmplexer.cc
Merge pull request #4163 from pieterlexis/license-woes
[thirdparty/pdns.git] / pdns / devpollmplexer.cc
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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 /*
26 * NOTE: sys/devpoll.h relies on sigset_t being already defined so we need
27 * to include sys/signal.h *before* including sys/devpoll.h.
28 */
29 #include <sys/signal.h>
30 #include <sys/devpoll.h>
31 #include "mplexer.hh"
32 #include "sstuff.hh"
33 #include <iostream>
34 #include <unistd.h>
35 #include "misc.hh"
36 #include "syncres.hh"
37
38 #include "namespaces.hh"
39 #include "namespaces.hh"
40
41 class DevPollFDMultiplexer : public FDMultiplexer
42 {
43 public:
44 DevPollFDMultiplexer();
45 virtual ~DevPollFDMultiplexer()
46 {
47 close(d_devpollfd);
48 }
49
50 virtual int run(struct timeval* tv);
51
52 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter);
53 virtual void removeFD(callbackmap_t& cbmap, int fd);
54 string getName()
55 {
56 return "/dev/poll";
57 }
58 private:
59 int d_devpollfd;
60 };
61
62
63 static FDMultiplexer* makeDevPoll()
64 {
65 return new DevPollFDMultiplexer();
66 }
67
68 static struct DevPollRegisterOurselves
69 {
70 DevPollRegisterOurselves() {
71 FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makeDevPoll)); // priority 0!
72 }
73 } doItDevPoll;
74
75
76 //int DevPollFDMultiplexer::s_maxevents=1024;
77 DevPollFDMultiplexer::DevPollFDMultiplexer()
78 {
79 d_devpollfd=open("/dev/poll", O_RDWR);
80 if(d_devpollfd < 0)
81 throw FDMultiplexerException("Setting up /dev/poll: "+stringerror());
82
83 }
84
85 void DevPollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)
86 {
87 accountingAddFD(cbmap, fd, toDo, parameter);
88
89 struct pollfd devent;
90 devent.fd=fd;
91 devent.events= (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT;
92 devent.revents = 0;
93
94 if(write(d_devpollfd, &devent, sizeof(devent)) != sizeof(devent)) {
95 cbmap.erase(fd);
96 throw FDMultiplexerException("Adding fd to /dev/poll/ set: "+stringerror());
97 }
98 }
99
100 void DevPollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
101 {
102 if(!cbmap.erase(fd))
103 throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
104
105 struct pollfd devent;
106 devent.fd=fd;
107 devent.events= POLLREMOVE;
108 devent.revents = 0;
109
110 if(write(d_devpollfd, &devent, sizeof(devent)) != sizeof(devent)) {
111 cbmap.erase(fd);
112 throw FDMultiplexerException("Removing fd from epoll set: "+stringerror());
113 }
114 }
115
116 int DevPollFDMultiplexer::run(struct timeval* now)
117 {
118 if(d_inrun) {
119 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
120 }
121 struct dvpoll dvp;
122 dvp.dp_nfds = d_readCallbacks.size() + d_writeCallbacks.size();
123 dvp.dp_fds = new pollfd[dvp.dp_nfds];
124 dvp.dp_timeout = 500;
125 int ret=ioctl(d_devpollfd, DP_POLL, &dvp);
126 gettimeofday(now,0); // MANDATORY!
127
128 if(ret < 0 && errno!=EINTR) {
129 delete[] dvp.dp_fds;
130 throw FDMultiplexerException("/dev/poll returned error: "+stringerror());
131 }
132
133 if(ret < 1) { // thanks AB!
134 delete[] dvp.dp_fds;
135 return 0;
136 }
137
138 d_inrun=true;
139 for(int n=0; n < ret; ++n) {
140 d_iter=d_readCallbacks.find(dvp.dp_fds[n].fd);
141
142 if(d_iter != d_readCallbacks.end()) {
143 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
144 continue; // so we don't refind ourselves as writable!
145 }
146 d_iter=d_writeCallbacks.find(dvp.dp_fds[n].fd);
147
148 if(d_iter != d_writeCallbacks.end()) {
149 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
150 }
151 }
152 delete[] dvp.dp_fds;
153 d_inrun=false;
154 return 0;
155 }
156
157 #if 0
158 void acceptData(int fd, funcparam_t& parameter)
159 {
160 cout<<"Have data on fd "<<fd<<endl;
161 Socket* sock=funcparam_t_cast<Socket*>(parameter);
162 string packet;
163 IPEndpoint rem;
164 sock->recvFrom(packet, rem);
165 cout<<"Received "<<packet.size()<<" bytes!\n";
166 }
167
168
169 int main()
170 {
171 Socket s(AF_INET, SOCK_DGRAM);
172
173 IPEndpoint loc("0.0.0.0", 2000);
174 s.bind(loc);
175
176 DevPollFDMultiplexer sfm;
177
178 sfm.addReadFD(s.getHandle(), &acceptData, &s);
179
180 for(int n=0; n < 100 ; ++n) {
181 sfm.run();
182 }
183 sfm.removeReadFD(s.getHandle());
184 sfm.removeReadFD(s.getHandle());
185 }
186 #endif
187
188