]>
Commit | Line | Data |
---|---|---|
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 | |
35 | class FDMultiplexerException : public std::runtime_error | |
36 | { | |
37 | public: | |
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 |
50 | class FDMultiplexer |
51 | { | |
d8f6d49f | 52 | public: |
d8f6d49f | 53 | typedef boost::any funcparam_t; |
ab3e8a6c | 54 | protected: |
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 | ||
64 | public: | |
65 | FDMultiplexer() : d_inrun(false) | |
66 | {} | |
67 | virtual ~FDMultiplexer() | |
68 | {} | |
69 | ||
0e663c3b RG |
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; | |
ab3e8a6c | 73 | |
a1dfcec8 | 74 | //! Add an fd to the read watch list - currently an fd can only be on one list at a time! |
d8f6d49f | 75 | virtual void addReadFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t()) |
ab3e8a6c | 76 | { |
a1dfcec8 | 77 | this->addFD(d_readCallbacks, fd, toDo, parameter); |
ab3e8a6c BH |
78 | } |
79 | ||
a1dfcec8 | 80 | //! Add an fd to the write watch list - currently an fd can only be on one list at a time! |
d8f6d49f | 81 | virtual void addWriteFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t()) |
ab3e8a6c | 82 | { |
a1dfcec8 | 83 | this->addFD(d_writeCallbacks, fd, toDo, parameter); |
ab3e8a6c BH |
84 | } |
85 | ||
a1dfcec8 | 86 | //! Remove an fd from the read watch list. You can't call this function on an fd that is closed already! |
6dcd28c3 | 87 | /** WARNING: references to 'parameter' become invalid after this function! */ |
ab3e8a6c BH |
88 | virtual void removeReadFD(int fd) |
89 | { | |
a1dfcec8 | 90 | this->removeFD(d_readCallbacks, fd); |
ab3e8a6c BH |
91 | } |
92 | ||
a1dfcec8 | 93 | //! Remove an fd from the write watch list. You can't call this function on an fd that is closed already! |
6dcd28c3 | 94 | /** WARNING: references to 'parameter' become invalid after this function! */ |
a1dfcec8 | 95 | virtual void removeWriteFD(int fd) |
ab3e8a6c | 96 | { |
a1dfcec8 | 97 | this->removeFD(d_writeCallbacks, fd); |
ab3e8a6c BH |
98 | } |
99 | ||
0bff046b BH |
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 | ||
d8f6d49f | 108 | virtual funcparam_t& getReadParameter(int fd) |
a6ae6414 BH |
109 | { |
110 | if(!d_readCallbacks.count(fd)) | |
335da0ba | 111 | throw FDMultiplexerException("attempt to look up data in multiplexer for unlisted fd "+std::to_string(fd)); |
a6ae6414 BH |
112 | return d_readCallbacks[fd].d_parameter; |
113 | } | |
114 | ||
d8f6d49f | 115 | virtual std::vector<std::pair<int, funcparam_t> > getTimeouts(const struct timeval& tv) |
0bff046b | 116 | { |
d8f6d49f | 117 | std::vector<std::pair<int, funcparam_t> > ret; |
0bff046b BH |
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)) | |
4957a608 | 120 | ret.push_back(std::make_pair(i->first, i->second.d_parameter)); |
0bff046b BH |
121 | return ret; |
122 | } | |
123 | ||
1f4abb20 BH |
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 | ||
ab3e8a6c BH |
135 | protected: |
136 | typedef std::map<int, Callback> callbackmap_t; | |
137 | callbackmap_t d_readCallbacks, d_writeCallbacks; | |
ab3e8a6c | 138 | |
d8f6d49f | 139 | virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)=0; |
ab3e8a6c BH |
140 | virtual void removeFD(callbackmap_t& cbmap, int fd)=0; |
141 | bool d_inrun; | |
a1dfcec8 | 142 | callbackmap_t::iterator d_iter; |
c454d11b | 143 | |
d8f6d49f | 144 | void accountingAddFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter) |
c454d11b BH |
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)) | |
335da0ba | 152 | throw FDMultiplexerException("Tried to add fd "+std::to_string(fd)+ " to multiplexer twice"); |
c454d11b BH |
153 | cbmap[fd]=cb; |
154 | } | |
155 | ||
156 | void accountingRemoveFD(callbackmap_t& cbmap, int fd) | |
157 | { | |
158 | if(!cbmap.erase(fd)) | |
335da0ba | 159 | throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); |
c454d11b | 160 | } |
1f4abb20 BH |
161 | }; |
162 | ||
163 | class SelectFDMultiplexer : public FDMultiplexer | |
164 | { | |
165 | public: | |
166 | SelectFDMultiplexer() | |
167 | {} | |
168 | virtual ~SelectFDMultiplexer() | |
169 | {} | |
ab3e8a6c | 170 | |
0e663c3b | 171 | virtual int run(struct timeval* tv, int timeout=500); |
1f4abb20 | 172 | |
d8f6d49f | 173 | virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter); |
1f4abb20 BH |
174 | virtual void removeFD(callbackmap_t& cbmap, int fd); |
175 | std::string getName() | |
176 | { | |
177 | return "select"; | |
178 | } | |
ab3e8a6c BH |
179 | }; |
180 | ||
a7acf71b AT |
181 | #endif |
182 |