]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/epollmplexer.cc
Merge pull request #5509 from zeha/f/ship-ldap-schema
[thirdparty/pdns.git] / pdns / epollmplexer.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 #include "mplexer.hh"
26 #include "sstuff.hh"
27 #include <iostream>
28 #include <unistd.h>
29 #include "misc.hh"
30 #ifdef __linux__
31 #include <sys/epoll.h>
32 #endif
33
34 #include "namespaces.hh"
35 #include "namespaces.hh"
36
37 class EpollFDMultiplexer : public FDMultiplexer
38 {
39 public:
40 EpollFDMultiplexer();
41 virtual ~EpollFDMultiplexer()
42 {
43 close(d_epollfd);
44 }
45
46 virtual int run(struct timeval* tv);
47
48 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter);
49 virtual void removeFD(callbackmap_t& cbmap, int fd);
50 string getName()
51 {
52 return "epoll";
53 }
54 private:
55 int d_epollfd;
56 boost::shared_array<epoll_event> d_eevents;
57 static int s_maxevents; // not a hard maximum
58 };
59
60
61 static FDMultiplexer* makeEpoll()
62 {
63 return new EpollFDMultiplexer();
64 }
65
66 static struct EpollRegisterOurselves
67 {
68 EpollRegisterOurselves() {
69 FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makeEpoll)); // priority 0!
70 }
71 } doItEpoll;
72
73
74 int EpollFDMultiplexer::s_maxevents=1024;
75 EpollFDMultiplexer::EpollFDMultiplexer() : d_eevents(new epoll_event[s_maxevents])
76 {
77 d_epollfd=epoll_create(s_maxevents); // not hard max
78 if(d_epollfd < 0)
79 throw FDMultiplexerException("Setting up epoll: "+stringerror());
80 int fd=socket(AF_INET, SOCK_DGRAM, 0); // for self-test
81 if(fd < 0)
82 return;
83 try {
84 addReadFD(fd, 0);
85 removeReadFD(fd);
86 close(fd);
87 return;
88 }
89 catch(FDMultiplexerException &fe) {
90 close(fd);
91 close(d_epollfd);
92 throw FDMultiplexerException("epoll multiplexer failed self-test: "+string(fe.what()));
93 }
94
95 }
96
97 void EpollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)
98 {
99 accountingAddFD(cbmap, fd, toDo, parameter);
100
101 struct epoll_event eevent;
102
103 eevent.events = (&cbmap == &d_readCallbacks) ? EPOLLIN : EPOLLOUT;
104
105 eevent.data.u64=0; // placate valgrind (I love it so much)
106 eevent.data.fd=fd;
107
108 if(epoll_ctl(d_epollfd, EPOLL_CTL_ADD, fd, &eevent) < 0) {
109 cbmap.erase(fd);
110 throw FDMultiplexerException("Adding fd to epoll set: "+stringerror());
111 }
112 }
113
114 void EpollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
115 {
116 if(!cbmap.erase(fd))
117 throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
118
119 struct epoll_event dummy;
120 dummy.events = 0;
121 dummy.data.u64 = 0;
122
123 if(epoll_ctl(d_epollfd, EPOLL_CTL_DEL, fd, &dummy) < 0)
124 throw FDMultiplexerException("Removing fd from epoll set: "+stringerror());
125 }
126
127 int EpollFDMultiplexer::run(struct timeval* now)
128 {
129 if(d_inrun) {
130 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
131 }
132
133 int ret=epoll_wait(d_epollfd, d_eevents.get(), s_maxevents, 500);
134 gettimeofday(now,0); // MANDATORY
135
136 if(ret < 0 && errno!=EINTR)
137 throw FDMultiplexerException("epoll returned error: "+stringerror());
138
139 if(ret < 1) // thanks AB!
140 return 0;
141
142 d_inrun=true;
143 for(int n=0; n < ret; ++n) {
144 d_iter=d_readCallbacks.find(d_eevents[n].data.fd);
145
146 if(d_iter != d_readCallbacks.end()) {
147 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
148 continue; // so we don't refind ourselves as writable!
149 }
150 d_iter=d_writeCallbacks.find(d_eevents[n].data.fd);
151
152 if(d_iter != d_writeCallbacks.end()) {
153 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
154 }
155 }
156 d_inrun=false;
157 return 0;
158 }
159
160 #if 0
161 void acceptData(int fd, funcparam_t& parameter)
162 {
163 cout<<"Have data on fd "<<fd<<endl;
164 Socket* sock=funcparam_t_cast<Socket*>(parameter);
165 string packet;
166 IPEndpoint rem;
167 sock->recvFrom(packet, rem);
168 cout<<"Received "<<packet.size()<<" bytes!\n";
169 }
170
171
172 int main()
173 {
174 Socket s(AF_INET, SOCK_DGRAM);
175
176 IPEndpoint loc("0.0.0.0", 2000);
177 s.bind(loc);
178
179 EpollFDMultiplexer sfm;
180
181 sfm.addReadFD(s.getHandle(), &acceptData, &s);
182
183 for(int n=0; n < 100 ; ++n) {
184 sfm.run();
185 }
186 sfm.removeReadFD(s.getHandle());
187 sfm.removeReadFD(s.getHandle());
188 }
189 #endif
190
191