]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/mplexer.hh
rec: Don't account chained queries more than once
[thirdparty/pdns.git] / pdns / mplexer.hh
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 #ifndef PDNS_MPLEXER_HH
23 #define PDNS_MPLEXER_HH
24 #include <boost/function.hpp>
25 #include <boost/any.hpp>
26 #include <boost/shared_array.hpp>
27 #include <boost/tuple/tuple.hpp>
28 #include <boost/tuple/tuple_comparison.hpp>
29 #include <vector>
30 #include <map>
31 #include <stdexcept>
32 #include <string>
33 #include <sys/time.h>
34
35 class FDMultiplexerException : public std::runtime_error
36 {
37 public:
38 FDMultiplexerException(const std::string& str) : std::runtime_error(str)
39 {}
40 };
41
42
43 /** Very simple FD multiplexer, based on callbacks and boost::any parameters
44 As a special service, this parameter is kept around and can be modified,
45 allowing for state to be stored inside the multiplexer.
46
47 It has some "interesting" semantics
48 */
49
50 class FDMultiplexer
51 {
52 public:
53 typedef boost::any funcparam_t;
54 protected:
55
56 typedef boost::function< void(int, funcparam_t&) > callbackfunc_t;
57 struct Callback
58 {
59 callbackfunc_t d_callback;
60 funcparam_t d_parameter;
61 struct timeval d_ttd;
62 };
63
64 public:
65 FDMultiplexer() : d_inrun(false)
66 {}
67 virtual ~FDMultiplexer()
68 {}
69
70 /* tv will be updated to 'now' before run returns */
71 /* timeout is in ms */
72 virtual int run(struct timeval* tv, int timeout=500) = 0;
73
74 //! Add an fd to the read watch list - currently an fd can only be on one list at a time!
75 virtual void addReadFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t())
76 {
77 this->addFD(d_readCallbacks, fd, toDo, parameter);
78 }
79
80 //! Add an fd to the write watch list - currently an fd can only be on one list at a time!
81 virtual void addWriteFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t())
82 {
83 this->addFD(d_writeCallbacks, fd, toDo, parameter);
84 }
85
86 //! Remove an fd from the read watch list. You can't call this function on an fd that is closed already!
87 /** WARNING: references to 'parameter' become invalid after this function! */
88 virtual void removeReadFD(int fd)
89 {
90 this->removeFD(d_readCallbacks, fd);
91 }
92
93 //! Remove an fd from the write watch list. You can't call this function on an fd that is closed already!
94 /** WARNING: references to 'parameter' become invalid after this function! */
95 virtual void removeWriteFD(int fd)
96 {
97 this->removeFD(d_writeCallbacks, fd);
98 }
99
100 virtual void setReadTTD(int fd, struct timeval tv, int timeout)
101 {
102 if(!d_readCallbacks.count(fd))
103 throw FDMultiplexerException("attempt to timestamp fd not in the multiplexer");
104 tv.tv_sec += timeout;
105 d_readCallbacks[fd].d_ttd=tv;
106 }
107
108 virtual funcparam_t& getReadParameter(int fd)
109 {
110 if(!d_readCallbacks.count(fd))
111 throw FDMultiplexerException("attempt to look up data in multiplexer for unlisted fd "+std::to_string(fd));
112 return d_readCallbacks[fd].d_parameter;
113 }
114
115 virtual std::vector<std::pair<int, funcparam_t> > getTimeouts(const struct timeval& tv)
116 {
117 std::vector<std::pair<int, funcparam_t> > ret;
118 for(callbackmap_t::iterator i=d_readCallbacks.begin(); i!=d_readCallbacks.end(); ++i)
119 if(i->second.d_ttd.tv_sec && boost::tie(tv.tv_sec, tv.tv_usec) > boost::tie(i->second.d_ttd.tv_sec, i->second.d_ttd.tv_usec))
120 ret.push_back(std::make_pair(i->first, i->second.d_parameter));
121 return ret;
122 }
123
124 typedef FDMultiplexer* getMultiplexer_t();
125 typedef std::multimap<int, getMultiplexer_t*> FDMultiplexermap_t;
126
127 static FDMultiplexermap_t& getMultiplexerMap()
128 {
129 static FDMultiplexermap_t theMap;
130 return theMap;
131 }
132
133 virtual std::string getName() = 0;
134
135 protected:
136 typedef std::map<int, Callback> callbackmap_t;
137 callbackmap_t d_readCallbacks, d_writeCallbacks;
138
139 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)=0;
140 virtual void removeFD(callbackmap_t& cbmap, int fd)=0;
141 bool d_inrun;
142 callbackmap_t::iterator d_iter;
143
144 void accountingAddFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)
145 {
146 Callback cb;
147 cb.d_callback=toDo;
148 cb.d_parameter=parameter;
149 memset(&cb.d_ttd, 0, sizeof(cb.d_ttd));
150
151 if(cbmap.count(fd))
152 throw FDMultiplexerException("Tried to add fd "+std::to_string(fd)+ " to multiplexer twice");
153 cbmap[fd]=cb;
154 }
155
156 void accountingRemoveFD(callbackmap_t& cbmap, int fd)
157 {
158 if(!cbmap.erase(fd))
159 throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
160 }
161 };
162
163 class SelectFDMultiplexer : public FDMultiplexer
164 {
165 public:
166 SelectFDMultiplexer()
167 {}
168 virtual ~SelectFDMultiplexer()
169 {}
170
171 virtual int run(struct timeval* tv, int timeout=500);
172
173 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter);
174 virtual void removeFD(callbackmap_t& cbmap, int fd);
175 std::string getName()
176 {
177 return "select";
178 }
179 };
180
181 #endif
182