/* doscan - Denial Of Service Capable Auditing of Networks -*- C++ -*- * Copyright (C) 2003 Florian Weimer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EVENT_QUEUE_H #define EVENT_QUEUE_H #include "ticks.h" #include #include /* * event_queue * * An event_queue object handles file descriptor activity and * timeouts. Pure timeout handlers use event_queue::handler, handlers * for file descriptors use event_queue::fd_handler. For every file * descriptor, there is an associated timeout (and fd_handler derives * from handler). * * handler and fd_handler objects may only be created using operator * new. Memory they are automatically added to the corresponding * event queue, which is also responsible for freeing the handlers. * Destructors of handlers shall not perform any complicated activity * (such as adding new handlers). * * When you have create some handler objects, you may invoke * event_queue::run(). This will start the queue runner. run() will * return if there are no more active handlers. * * Explicit deallocation of handlers is not recommended. Handlers are * automatically deallocated when one of the on_*() member functions * returns false. To trigger deallocation, you can move the handler * to an application-specific final state and call set_timeout(0); the * on_timeout() member function detects this and returns false. For * fd_handler objects. you may also want to call unwatch(). * */ class event_queue { public: class handler; class fd_handler; private: struct handler_compare_timeout : public std::binary_function { bool operator()(const handler*, const handler*) const; }; typedef std::multiset timeouts_t; public: class handler { friend class event_queue; friend class handler_compare_timeout; handler(); // do not call handler(const handler&); // do not call handler& operator=(const handler&); // do not call protected: event_queue& m_queue; private: ticks_t timeout; timeouts_t::iterator timeout_ptr; bool compare_timeout(const handler& that) const; public: handler(event_queue&); virtual ~handler(); event_queue& queue() const; virtual bool on_timeout(ticks_t) = 0; // Returns true if the handler shall continue, otherwise it will // be deleted. The argument indicates the time when the timeout // occured (this might not be the current time). void set_absolute_timeout(ticks_t); void set_relative_timeout(ticks_t); void set_immediate_timeout(); void set_infinite_timeout(); }; class fd_handler : public handler { fd_handler(); // do not call fd_handler(const fd_handler&); // do not call fd_handler& operator=(const fd_handler&); // do not call int real_fd; bool compare_fd(const fd_handler& that) const; public: typedef enum { watch_read = 1, watch_write = 2, watch_read_write = 3 } watch_options; typedef enum { activity_read = 1, activity_write = 2, activity_read_write = 3, activity_error } activity; fd_handler(event_queue& q, int fd, watch_options); ~fd_handler(); int fd() const; // Returns the watched file descriptor. virtual bool on_activity(activity) = 0; // Returns true if the handler shall continue, otherwise it's // deleted. void watch(int fd, watch_options); void watch(watch_options); void unwatch(); // No longer watch fd. We still wait for the timeout. }; private: timeouts_t timeouts; // Saves the time at the start of a dispatching run. ticks_t dispatch_start_ticks; protected: // The following routines have to be overridden by decending // classes. They glue together the fd_handler activity and the I/O // multiplexing implementation. add_fd() adds a fresh handler, // update_fd() changes an existing handler, and remove_fd() removes // a handler. virtual void add_fd(fd_handler*, fd_handler::watch_options) = 0; virtual void update_fd(fd_handler*, fd_handler::watch_options) = 0; virtual void remove_fd(fd_handler*); // Before you can invoke fd_handler::on_activity(), you should use // this routine. It saves the current time so that we get a // consistent cut. void dispatch_start(); // Should be invoked after all calls to fd_handler::on_activity(). void dispatch_end(); // next_timeout() returns the next (relevative) timeout in // milliseconds, zero if an immediate timeout is required, and a // -1 for an infinite timeout. int next_timeout(); public: event_queue(); virtual ~event_queue(); virtual void run() = 0; // Creates an event queue that is optimized for this system. static event_queue* create(unsigned size_hint); // Prints the listeners to std::cerr. void dump(); }; // handler_compare_timeout inline bool event_queue::handler_compare_timeout::operator()(const handler* left, const handler* right) const { return left->timeout < right->timeout; } // handler inline bool event_queue::handler::compare_timeout(const event_queue::handler& that) const { return timeout < that.timeout; } inline event_queue& event_queue::handler::queue() const { return m_queue; } inline void event_queue::handler::set_relative_timeout(ticks_t ticks) { set_absolute_timeout(ticks_get_cached() + ticks); } inline void event_queue::handler::set_immediate_timeout() { set_absolute_timeout(0); } inline void event_queue::handler::set_infinite_timeout() { set_absolute_timeout(TICKS_LAST); } // fd_handler inline bool event_queue::fd_handler::compare_fd(const fd_handler& that) const { return fd() < that.fd(); } inline int event_queue::fd_handler::fd() const { return real_fd; } inline void event_queue::fd_handler::watch(watch_options w) { m_queue.update_fd(this, w); } // event_queue inline void event_queue::dispatch_start() { dispatch_start_ticks = ticks_get(); } #endif // EVENT_QUEUE_H // arch-tag: 7effa62b-710c-4525-9a72-5565e5e2c2bc