]>
Commit | Line | Data |
---|---|---|
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 | |
15 | class FDMultiplexerException : public std::runtime_error | |
16 | { | |
17 | public: | |
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 |
30 | class FDMultiplexer |
31 | { | |
d8f6d49f BH |
32 | public: |
33 | // typedef boost::variant<PacketID, TCPConnection> funcparam_t; | |
34 | typedef boost::any funcparam_t; | |
ab3e8a6c | 35 | protected: |
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 | ||
45 | public: | |
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 |
115 | protected: |
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 | ||
143 | class SelectFDMultiplexer : public FDMultiplexer | |
144 | { | |
145 | public: | |
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 |