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