root/trunk/pdns/pdns/mplexer.hh @ 722

Revision 722, 4.5 KB (checked in by ahu, 7 years ago)

fix timeouts of running TCP client queries - we shouldn't time them out while we are still working!

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