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