]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/kqueuemplexer.cc
Merge branch 'validate-hostname' of https://github.com/hlindqvist/pdns into hlindqvis...
[thirdparty/pdns.git] / pdns / kqueuemplexer.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 #include <sys/types.h>
32 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
33 #include <sys/event.h>
34 #endif
35 #include <sys/time.h>
36
37 #include "namespaces.hh"
38 #include "namespaces.hh"
39
40 class KqueueFDMultiplexer : public FDMultiplexer
41 {
42 public:
43 KqueueFDMultiplexer();
44 virtual ~KqueueFDMultiplexer()
45 {
46 close(d_kqueuefd);
47 }
48
49 virtual int run(struct timeval* tv);
50
51 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter);
52 virtual void removeFD(callbackmap_t& cbmap, int fd);
53 string getName()
54 {
55 return "kqueue";
56 }
57 private:
58 int d_kqueuefd;
59 boost::shared_array<struct kevent> d_kevents;
60 static unsigned int s_maxevents; // not a hard maximum
61 };
62
63 unsigned int KqueueFDMultiplexer::s_maxevents=1024;
64
65 static FDMultiplexer* make()
66 {
67 return new KqueueFDMultiplexer();
68 }
69
70 static struct KqueueRegisterOurselves
71 {
72 KqueueRegisterOurselves() {
73 FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &make)); // priority 0!
74 }
75 } kQueuedoIt;
76
77 KqueueFDMultiplexer::KqueueFDMultiplexer() : d_kevents(new struct kevent[s_maxevents])
78 {
79 d_kqueuefd=kqueue();
80 if(d_kqueuefd < 0)
81 throw FDMultiplexerException("Setting up kqueue: "+stringerror());
82 }
83
84 void KqueueFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter)
85 {
86 accountingAddFD(cbmap, fd, toDo, parameter);
87
88 struct kevent kqevent;
89 EV_SET(&kqevent, fd, (&cbmap == &d_readCallbacks) ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0,0,0);
90
91 if(kevent(d_kqueuefd, &kqevent, 1, 0, 0, 0) < 0) {
92 cbmap.erase(fd);
93 throw FDMultiplexerException("Adding fd to kqueue set: "+stringerror());
94 }
95 }
96
97 void KqueueFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
98 {
99 accountingRemoveFD(cbmap, fd);
100
101 struct kevent kqevent;
102 EV_SET(&kqevent, fd, (&cbmap == &d_readCallbacks) ? EVFILT_READ : EVFILT_WRITE, EV_DELETE, 0,0,0);
103
104 if(kevent(d_kqueuefd, &kqevent, 1, 0, 0, 0) < 0) // ponder putting Callback back on the map..
105 throw FDMultiplexerException("Removing fd from kqueue set: "+stringerror());
106 }
107
108 int KqueueFDMultiplexer::run(struct timeval* now)
109 {
110 if(d_inrun) {
111 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
112 }
113
114 struct timespec ts;
115 ts.tv_sec=0;
116 ts.tv_nsec=500000000U;
117
118 int ret=kevent(d_kqueuefd, 0, 0, d_kevents.get(), s_maxevents, &ts);
119 gettimeofday(now,0); // MANDATORY!
120
121 if(ret < 0 && errno!=EINTR)
122 throw FDMultiplexerException("kqueue returned error: "+stringerror());
123
124 if(ret < 0) // nothing - thanks AB!
125 return 0;
126
127 d_inrun=true;
128
129 for(int n=0; n < ret; ++n) {
130 d_iter=d_readCallbacks.find(d_kevents[n].ident);
131 if(d_iter != d_readCallbacks.end()) {
132 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
133 continue; // so we don't find ourselves as writable again
134 }
135
136 d_iter=d_writeCallbacks.find(d_kevents[n].ident);
137
138 if(d_iter != d_writeCallbacks.end()) {
139 d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
140 }
141 }
142
143 d_inrun=false;
144 return 0;
145 }
146
147 #if 0
148 void acceptData(int fd, boost::any& parameter)
149 {
150 cout<<"Have data on fd "<<fd<<endl;
151 Socket* sock=boost::any_cast<Socket*>(parameter);
152 string packet;
153 IPEndpoint rem;
154 sock->recvFrom(packet, rem);
155 cout<<"Received "<<packet.size()<<" bytes!\n";
156 }
157
158 int main()
159 {
160 Socket s(AF_INET, SOCK_DGRAM);
161
162 IPEndpoint loc("0.0.0.0", 2000);
163 s.bind(loc);
164
165 KqueueFDMultiplexer sfm;
166
167 sfm.addReadFD(s.getHandle(), &acceptData, &s);
168
169 for(int n=0; n < 100 ; ++n) {
170 sfm.run();
171 }
172 sfm.removeReadFD(s.getHandle());
173 sfm.removeReadFD(s.getHandle());
174 }
175 #endif
176
177
178