]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/mplexer.hh
Only allocate the SSocket buffer when we actually need it, cleanup
[thirdparty/pdns.git] / pdns / mplexer.hh
CommitLineData
12471842
PL
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 */
8ecee27a
BH
22#ifndef PDNS_MPLEXER_HH
23#define PDNS_MPLEXER_HH
ab3e8a6c
BH
24#include <boost/function.hpp>
25#include <boost/any.hpp>
a1dfcec8 26#include <boost/shared_array.hpp>
0bff046b
BH
27#include <boost/tuple/tuple.hpp>
28#include <boost/tuple/tuple_comparison.hpp>
29#include <vector>
ab3e8a6c
BH
30#include <map>
31#include <stdexcept>
32#include <string>
f1d51ff7 33#include <sys/time.h>
ab3e8a6c
BH
34
35class FDMultiplexerException : public std::runtime_error
36{
37public:
38 FDMultiplexerException(const std::string& str) : std::runtime_error(str)
39 {}
40};
41
a1dfcec8
BH
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*/
1f4abb20 49
ab3e8a6c
BH
50class FDMultiplexer
51{
d8f6d49f 52public:
d8f6d49f 53 typedef boost::any funcparam_t;
ab3e8a6c 54protected:
d8f6d49f
BH
55
56 typedef boost::function< void(int, funcparam_t&) > callbackfunc_t;
ab3e8a6c
BH
57 struct Callback
58 {
59 callbackfunc_t d_callback;
d8f6d49f 60 funcparam_t d_parameter;
0bff046b 61 struct timeval d_ttd;
ab3e8a6c
BH
62 };
63
64public:
65 FDMultiplexer() : d_inrun(false)
66 {}
67 virtual ~FDMultiplexer()
68 {}
69
4226cfd0 70 static FDMultiplexer* getMultiplexerSilent();
71
0e663c3b
RG
72 /* tv will be updated to 'now' before run returns */
73 /* timeout is in ms */
74 virtual int run(struct timeval* tv, int timeout=500) = 0;
ab3e8a6c 75
5bdbb83d
RG
76 /* timeout is in ms, 0 will return immediatly, -1 will block until at least one FD is ready */
77 virtual void getAvailableFDs(std::vector<int>& fds, int timeout) = 0;
78
a1dfcec8 79 //! Add an fd to the read watch list - currently an fd can only be on one list at a time!
27ae2e3c 80 virtual void addReadFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t(), const struct timeval* ttd=nullptr)
ab3e8a6c 81 {
27ae2e3c 82 this->addFD(d_readCallbacks, fd, toDo, parameter, ttd);
ab3e8a6c
BH
83 }
84
a1dfcec8 85 //! Add an fd to the write watch list - currently an fd can only be on one list at a time!
702b1925 86 virtual void addWriteFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t(), const struct timeval* ttd=nullptr)
ab3e8a6c 87 {
702b1925 88 this->addFD(d_writeCallbacks, fd, toDo, parameter, ttd);
ab3e8a6c
BH
89 }
90
a1dfcec8 91 //! Remove an fd from the read watch list. You can't call this function on an fd that is closed already!
6dcd28c3 92 /** WARNING: references to 'parameter' become invalid after this function! */
ab3e8a6c
BH
93 virtual void removeReadFD(int fd)
94 {
a1dfcec8 95 this->removeFD(d_readCallbacks, fd);
ab3e8a6c
BH
96 }
97
a1dfcec8 98 //! Remove an fd from the write watch list. You can't call this function on an fd that is closed already!
6dcd28c3 99 /** WARNING: references to 'parameter' become invalid after this function! */
a1dfcec8 100 virtual void removeWriteFD(int fd)
ab3e8a6c 101 {
a1dfcec8 102 this->removeFD(d_writeCallbacks, fd);
ab3e8a6c
BH
103 }
104
0bff046b
BH
105 virtual void setReadTTD(int fd, struct timeval tv, int timeout)
106 {
27ae2e3c
RG
107 const auto& it = d_readCallbacks.find(fd);
108 if (it == d_readCallbacks.end()) {
0bff046b 109 throw FDMultiplexerException("attempt to timestamp fd not in the multiplexer");
27ae2e3c
RG
110 }
111
0bff046b 112 tv.tv_sec += timeout;
27ae2e3c 113 it->second.d_ttd = tv;
0bff046b
BH
114 }
115
702b1925
RG
116 virtual void setWriteTTD(int fd, struct timeval tv, int timeout)
117 {
118 const auto& it = d_writeCallbacks.find(fd);
119 if (it == d_writeCallbacks.end()) {
120 throw FDMultiplexerException("attempt to timestamp fd not in the multiplexer");
121 }
122
123 tv.tv_sec += timeout;
124 it->second.d_ttd = tv;
125 }
126
d8f6d49f 127 virtual funcparam_t& getReadParameter(int fd)
a6ae6414 128 {
27ae2e3c
RG
129 const auto& it = d_readCallbacks.find(fd);
130 if(it == d_readCallbacks.end()) {
335da0ba 131 throw FDMultiplexerException("attempt to look up data in multiplexer for unlisted fd "+std::to_string(fd));
27ae2e3c
RG
132 }
133
134 return it->second.d_parameter;
a6ae6414
BH
135 }
136
702b1925 137 virtual std::vector<std::pair<int, funcparam_t> > getTimeouts(const struct timeval& tv, bool writes=false)
0bff046b 138 {
27ae2e3c 139 const auto tied = boost::tie(tv.tv_sec, tv.tv_usec);
d8f6d49f 140 std::vector<std::pair<int, funcparam_t> > ret;
27ae2e3c 141
702b1925 142 for(const auto& entry : (writes ? d_writeCallbacks : d_readCallbacks)) {
27ae2e3c
RG
143 if(entry.second.d_ttd.tv_sec && tied > boost::tie(entry.second.d_ttd.tv_sec, entry.second.d_ttd.tv_usec)) {
144 ret.push_back(std::make_pair(entry.first, entry.second.d_parameter));
145 }
146 }
147
0bff046b
BH
148 return ret;
149 }
150
1f4abb20
BH
151 typedef FDMultiplexer* getMultiplexer_t();
152 typedef std::multimap<int, getMultiplexer_t*> FDMultiplexermap_t;
153
154 static FDMultiplexermap_t& getMultiplexerMap()
155 {
156 static FDMultiplexermap_t theMap;
157 return theMap;
158 }
159
5bdbb83d 160 virtual std::string getName() const = 0;
1f4abb20 161
ab3e8a6c
BH
162protected:
163 typedef std::map<int, Callback> callbackmap_t;
164 callbackmap_t d_readCallbacks, d_writeCallbacks;
ab3e8a6c 165
27ae2e3c 166 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd=nullptr)=0;
ab3e8a6c
BH
167 virtual void removeFD(callbackmap_t& cbmap, int fd)=0;
168 bool d_inrun;
a1dfcec8 169 callbackmap_t::iterator d_iter;
c454d11b 170
27ae2e3c 171 void accountingAddFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd=nullptr)
c454d11b
BH
172 {
173 Callback cb;
174 cb.d_callback=toDo;
175 cb.d_parameter=parameter;
176 memset(&cb.d_ttd, 0, sizeof(cb.d_ttd));
27ae2e3c
RG
177 if (ttd) {
178 cb.d_ttd = *ttd;
179 }
180
181 auto pair = cbmap.insert({fd, cb});
182 if (!pair.second) {
335da0ba 183 throw FDMultiplexerException("Tried to add fd "+std::to_string(fd)+ " to multiplexer twice");
27ae2e3c 184 }
c454d11b
BH
185 }
186
187 void accountingRemoveFD(callbackmap_t& cbmap, int fd)
188 {
27ae2e3c 189 if(!cbmap.erase(fd)) {
335da0ba 190 throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
27ae2e3c 191 }
c454d11b 192 }
1f4abb20
BH
193};
194
ab3e8a6c 195
a7acf71b
AT
196#endif
197