]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/mplexer.hh
Merge pull request #1268 from cmouse/recursor-nits
[thirdparty/pdns.git] / pdns / mplexer.hh
CommitLineData
8ecee27a
BH
1#ifndef PDNS_MPLEXER_HH
2#define PDNS_MPLEXER_HH
ab3e8a6c
BH
3#include <boost/function.hpp>
4#include <boost/any.hpp>
a1dfcec8 5#include <boost/shared_array.hpp>
0bff046b
BH
6#include <boost/tuple/tuple.hpp>
7#include <boost/tuple/tuple_comparison.hpp>
c454d11b 8#include <boost/lexical_cast.hpp>
0bff046b 9#include <vector>
ab3e8a6c
BH
10#include <map>
11#include <stdexcept>
12#include <string>
f14ebffb 13#include "utility.hh"
ab3e8a6c
BH
14
15class FDMultiplexerException : public std::runtime_error
16{
17public:
18 FDMultiplexerException(const std::string& str) : std::runtime_error(str)
19 {}
20};
21
a1dfcec8
BH
22
23/** Very simple FD multiplexer, based on callbacks and boost::any parameters
24 As a special service, this parameter is kept around and can be modified,
25 allowing for state to be stored inside the multiplexer.
26
27 It has some "interesting" semantics
28*/
1f4abb20 29
ab3e8a6c
BH
30class FDMultiplexer
31{
d8f6d49f
BH
32public:
33 // typedef boost::variant<PacketID, TCPConnection> funcparam_t;
34 typedef boost::any funcparam_t;
ab3e8a6c 35protected:
d8f6d49f
BH
36
37 typedef boost::function< void(int, funcparam_t&) > callbackfunc_t;
ab3e8a6c
BH
38 struct Callback
39 {
40 callbackfunc_t d_callback;
d8f6d49f 41 funcparam_t d_parameter;
0bff046b 42 struct timeval d_ttd;
ab3e8a6c
BH
43 };
44
45public:
46 FDMultiplexer() : d_inrun(false)
47 {}
48 virtual ~FDMultiplexer()
49 {}
50
0bff046b 51 virtual int run(struct timeval* tv) = 0;
ab3e8a6c 52
a1dfcec8 53 //! Add an fd to the read watch list - currently an fd can only be on one list at a time!
d8f6d49f 54 virtual void addReadFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t())
ab3e8a6c 55 {
a1dfcec8 56 this->addFD(d_readCallbacks, fd, toDo, parameter);
ab3e8a6c
BH
57 }
58
a1dfcec8 59 //! Add an fd to the write watch list - currently an fd can only be on one list at a time!
d8f6d49f 60 virtual void addWriteFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t())
ab3e8a6c 61 {
a1dfcec8 62 this->addFD(d_writeCallbacks, fd, toDo, parameter);
ab3e8a6c
BH
63 }
64
a1dfcec8 65 //! Remove an fd from the read watch list. You can't call this function on an fd that is closed already!
6dcd28c3 66 /** WARNING: references to 'parameter' become invalid after this function! */
ab3e8a6c
BH
67 virtual void removeReadFD(int fd)
68 {
a1dfcec8 69 this->removeFD(d_readCallbacks, fd);
ab3e8a6c
BH
70 }
71
a1dfcec8 72 //! Remove an fd from the write watch list. You can't call this function on an fd that is closed already!
6dcd28c3 73 /** WARNING: references to 'parameter' become invalid after this function! */
a1dfcec8 74 virtual void removeWriteFD(int fd)
ab3e8a6c 75 {
a1dfcec8 76 this->removeFD(d_writeCallbacks, fd);
ab3e8a6c
BH
77 }
78
0bff046b
BH
79 virtual void setReadTTD(int fd, struct timeval tv, int timeout)
80 {
81 if(!d_readCallbacks.count(fd))
82 throw FDMultiplexerException("attempt to timestamp fd not in the multiplexer");
83 tv.tv_sec += timeout;
84 d_readCallbacks[fd].d_ttd=tv;
85 }
86
d8f6d49f 87 virtual funcparam_t& getReadParameter(int fd)
a6ae6414
BH
88 {
89 if(!d_readCallbacks.count(fd))
90 throw FDMultiplexerException("attempt to look up data in multiplexer for unlisted fd "+boost::lexical_cast<std::string>(fd));
91 return d_readCallbacks[fd].d_parameter;
92 }
93
d8f6d49f 94 virtual std::vector<std::pair<int, funcparam_t> > getTimeouts(const struct timeval& tv)
0bff046b 95 {
d8f6d49f 96 std::vector<std::pair<int, funcparam_t> > ret;
0bff046b
BH
97 for(callbackmap_t::iterator i=d_readCallbacks.begin(); i!=d_readCallbacks.end(); ++i)
98 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 99 ret.push_back(std::make_pair(i->first, i->second.d_parameter));
0bff046b
BH
100 return ret;
101 }
102
1f4abb20
BH
103 typedef FDMultiplexer* getMultiplexer_t();
104 typedef std::multimap<int, getMultiplexer_t*> FDMultiplexermap_t;
105
106 static FDMultiplexermap_t& getMultiplexerMap()
107 {
108 static FDMultiplexermap_t theMap;
109 return theMap;
110 }
111
112 virtual std::string getName() = 0;
113
a6ae6414 114
ab3e8a6c
BH
115protected:
116 typedef std::map<int, Callback> callbackmap_t;
117 callbackmap_t d_readCallbacks, d_writeCallbacks;
ab3e8a6c 118
d8f6d49f 119 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)=0;
ab3e8a6c
BH
120 virtual void removeFD(callbackmap_t& cbmap, int fd)=0;
121 bool d_inrun;
a1dfcec8 122 callbackmap_t::iterator d_iter;
c454d11b 123
d8f6d49f 124 void accountingAddFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)
c454d11b
BH
125 {
126 Callback cb;
127 cb.d_callback=toDo;
128 cb.d_parameter=parameter;
129 memset(&cb.d_ttd, 0, sizeof(cb.d_ttd));
130
131 if(cbmap.count(fd))
132 throw FDMultiplexerException("Tried to add fd "+boost::lexical_cast<std::string>(fd)+ " to multiplexer twice");
133 cbmap[fd]=cb;
134 }
135
136 void accountingRemoveFD(callbackmap_t& cbmap, int fd)
137 {
138 if(!cbmap.erase(fd))
139 throw FDMultiplexerException("Tried to remove unlisted fd "+boost::lexical_cast<std::string>(fd)+ " from multiplexer");
140 }
1f4abb20
BH
141};
142
143class SelectFDMultiplexer : public FDMultiplexer
144{
145public:
146 SelectFDMultiplexer()
147 {}
148 virtual ~SelectFDMultiplexer()
149 {}
ab3e8a6c 150
0bff046b 151 virtual int run(struct timeval* tv);
1f4abb20 152
d8f6d49f 153 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter);
1f4abb20
BH
154 virtual void removeFD(callbackmap_t& cbmap, int fd);
155 std::string getName()
156 {
157 return "select";
158 }
ab3e8a6c
BH
159};
160
8ecee27a 161#endif