libasyncio: (tomj) fix uninitialized vars, added little safety against zombie filters
[libasyncio] / asyncio / async_io.hpp
1 /** 
2  * @file
3  * @brief simple basic IO handling.
4  *
5  * @copyright © Copyright 2007-2008 by Intra2net AG
6  * @license LGPL
7  * @contact info@intra2net.com
8  *
9  * Deals with POSIX file descriptors; provides an additional abstraction
10  * level above select() or poll() interface.
11  * Also provides basic functionality for dealing with timer events.
12  */
13
14 #ifndef __ASYNC_IO_HPP__
15 #define __ASYNC_IO_HPP__
16
17 #include <string>
18 #include <list>
19 #include <set>
20
21 #include <asyncio_utils.hpp>
22
23 #include <pointer_func.hpp>
24
25 #include <boost/signal.hpp>
26 #include <boost/shared_ptr.hpp>
27
28
29 namespace AsyncIo
30 {
31
32 using namespace I2n;
33 using Utils::MilliTime;
34
35 /*
36  * forward declarations
37  */
38 class Backend;
39 class IOImplementation;
40
41 /*
42  * end of forward declarations
43  */
44
45
46 /**
47  * direction for io operations.
48  */
49 struct Direction
50 {
51     enum _Direction
52     {
53         unspecified= 0,
54         in = 1,
55         out = 2,
56         both= 3
57     } m_direction;
58
59     Direction( _Direction direction = unspecified) : m_direction(direction) {}
60
61     operator _Direction () const { return m_direction; }
62 }; // eo struct IODirection;
63
64
65
66 /**
67  * base class for time based events (timer events).
68  *
69  * consists basically of a point in time (when the event should be executed) and a method
70  * which will be called when the given time is reached (or passed).
71  */
72 class TimerBase
73 {
74         friend class Backend;
75     public:
76         TimerBase();
77         virtual ~TimerBase();
78
79         bool active() const { return m_active; } 
80
81         MilliTime getWhenTime() const {return m_when;}
82         MilliTime getRealWhenTime() const;
83
84     protected:
85
86         void setWhenTime(long sec, long msec=0);
87         void setWhenTime(const MilliTime& mt);
88
89         void setDeltaWhenTime(long sec, long msec=0);
90         void setDeltaWhenTime(const MilliTime& mt);
91
92         void activate(bool _active= true);
93         void deactivate() { activate(false); }
94
95         virtual void execute();
96
97     private:
98         /// @a true when the event is active.
99         bool m_active;
100         /// point in time when the event should be executed
101         MilliTime m_when;
102         /// mark from backend cycle that the event has to be executed.
103         bool m_marked;
104 }; // eo class TimerBase
105
106
107
108 /**
109  * base class for filter classes.
110  *
111  * filter objects can be "plugged" into IO objects for manipulating the data streams.
112  * (for example: one could make a filter which handles the telnet protocol and plug it into a
113  * socket io object.)
114  *
115  * @note filter object can be used only by one io object.
116  */
117 class FilterBase
118 : virtual public SharedBase
119 {
120         friend class IOImplementation;
121     public:
122         typedef boost::shared_ptr< FilterBase > PtrType;
123     public:
124         FilterBase();
125         virtual ~FilterBase() { m_io = NULL; };
126
127     protected:
128
129         virtual std::string filterIncomingData(const std::string& data)= 0;
130         virtual std::string filterOutgoingData(const std::string& data)= 0;
131
132         virtual void endOfIncomingData();
133         virtual void reset();
134
135     protected:
136
137         void injectIncomingData(const std::string& data);
138         void injectOutgoingData(const std::string& data);
139
140     private:
141         /// pointer to the io object which uses this filter:
142         IOImplementation *m_io;
143 }; // eo class FilterBase
144
145 typedef FilterBase::PtrType FilterBasePtr;
146
147
148 /**
149  * identity filter; does nothing with the data (in other words: it's useless ;-) ).
150  */
151 class FilterIdentity : public FilterBase
152 {
153     protected:
154         virtual std::string filterIncomingData(const std::string& data) { return data; }
155         virtual std::string filterOutgoingData(const std::string& data) { return data; }
156 }; // eo class FilterIdentity
157
158
159 /**
160  * @brief null filter; deletes everything it receives.
161  *
162  * usefull when output from a subprocess (like stderr) should be ignored...
163  */
164 class FilterNull : public FilterBase
165 {
166     protected:
167         virtual std::string filterIncomingData(const std::string& data) { return std::string(); }
168         virtual std::string filterOutgoingData(const std::string& data) { return std::string(); }
169 }; // eo FilterNull
170
171
172 /**
173  * the base class of the IO classes.
174  *
175  * provides the functionality to read from a file desriptor and write to a file descriptor (which can be
176  * identical (like for socket io), but also can be different (like pipes from/to a process)).
177  * The data stream can be filtered through plugged filter objects which are building a filter chain.
178  * Incoming data is filtered forward through the chain; outgoing data is filtered backward through the chain.
179  * (So the first filter is the one which modifies the data closest to the connections).
180  *
181  * @note the functionality is provided in conjunction with the @a Backend class which handles parts of
182  * the low level IO.
183  *
184  * @note this is a base class; it provides most "interesting" functionality in the protected section only.
185  * This way, derived classes can decide which of that functionality they want to export in their own public
186  * interfaces and which to keep hidden.
187  */
188 class IOImplementation
189 : public boost::signals::trackable
190 , virtual public SharedBase
191 {
192         friend class Backend;
193         friend class FilterBase;
194
195     public:
196
197         typedef std::list< FilterBasePtr > FilterChain;
198
199         typedef boost::signal< void() > SignalType;
200
201         typedef boost::shared_ptr< IOImplementation > PtrType;
202
203     public:
204         IOImplementation(int read_fd=-1, int write_fd=-1);
205         virtual ~IOImplementation();
206
207         virtual void close(Direction direction = Direction::both);
208
209         virtual bool wantRead();
210         virtual bool wantWrite();
211
212         virtual bool opened() const;
213         virtual bool eof() const;
214         virtual bool writable() const;
215         virtual bool empty() const;
216
217     protected:
218
219         void addFilter(FilterBasePtr filter);
220         void removeFilter(FilterBasePtr);
221
222
223         void lowSend(const std::string& data);
224
225         std::string::size_type getOutputBufferSize() const { return m_output_buffer.size(); }
226
227         void setWriteFd(int fd);
228         void setReadFd(int fd);
229
230         inline int readFd() const
231         {
232             return m_read_fd;
233         }
234
235         inline int writeFd() const
236         {
237             return m_write_fd;
238         }
239
240         inline bool isMarkedForReading() const { return m_marked_for_reading; }
241         inline bool isMarkedForWriting() const { return m_marked_for_writing; }
242
243
244     protected:
245         virtual void doRead();
246         virtual void doWrite();
247
248         void resetReadMark()  { m_marked_for_reading= false; }
249         void resetWriteMark() { m_marked_for_writing= false; }
250
251         void injectIncomingData(FilterBasePtr from_filter, const std::string& _data);
252         void injectOutgoingData(FilterBasePtr from_filter, const std::string& _data);
253
254     protected:
255         /// last error number
256         int m_errno;
257         /// the input buffer (i.e. the data read from @a m_read_fd)
258         std::string m_input_buffer;
259
260         /// the chain of filter which are applied to the data received are the data which should be send.
261         FilterChain m_filter_chain;
262
263         /// signal which is fired when end of file is detected
264         SignalType m_signal_eof;
265         /// signal which is fired when write is no longer possible
266         SignalType m_signal_not_writable;
267         /// signal which is fired when new data was read
268         SignalType m_signal_read;
269         /// signal which is fired when data was written
270         SignalType m_signal_write;
271
272         /// end of file (on @a m_read_fd) detected (used additionally when m_read_fd is valid)
273         bool m_eof;
274
275         /// unable-to-write (on @a m_write_fd) detected (used additionally when m_write_fd is valid)
276         bool m_not_writable;
277
278     private:
279         /// the file descriptor to read from (-1 if none is given)
280         int m_read_fd;
281         /// the file descriptor to write to (-1 if none is given)
282         int m_write_fd;
283         /// output buffer; contains the data which needs to be written.
284         std::string m_output_buffer;
285
286     private:
287         /// @a true when data is available to be read
288         bool m_marked_for_reading;
289         /// @a true when data can be written
290         bool m_marked_for_writing;
291
292 }; // eo class IOImplementation
293
294
295
296 /**
297  * same as IOImplementation, but makes fd access functions public.
298  */
299 class IOImplementation2 : public IOImplementation
300 {
301         typedef IOImplementation inherited;
302     public:
303         IOImplementation2(int read_fd=-1, int write_fd=-1) : inherited(read_fd, write_fd) {}
304
305         void setWriteFd(int fd) { inherited::setWriteFd(fd); }
306         void setReadFd(int fd)  { inherited::setReadFd(fd); }
307
308         int readFd() const { return inherited::readFd(); }
309         int writeFd() const { return inherited::writeFd(); }
310
311 }; // eo class IOImplementation2
312
313
314 /**
315  * provides sending data and receiving data via a signal.
316  *
317  * @note the received data is passed as parameter to the signal and no longer stored in the received buffer.
318  */
319 class SimpleIO : public IOImplementation
320 {
321         typedef IOImplementation inherited;
322     public:
323         SimpleIO(int read_fd=-1, int write_fd=-1);
324         virtual ~SimpleIO();
325
326         void sendString(const std::string& data);
327
328         boost::signal<void(const std::string&)> signal_received_string;
329
330     private:
331
332         void slotReceived();
333 }; // eo class SimpleIO
334
335
336 /**
337  * provides sending data and receiving data via a signal.
338  *
339  * @note the received data is passed as parameter to the signal and no longer stored in the received buffer.
340  */
341 class SimpleIO2 : public IOImplementation2
342 {
343         typedef IOImplementation2 inherited;
344     public:
345         SimpleIO2(int read_fd=-1, int write_fd=-1);
346         virtual ~SimpleIO2();
347
348         void sendString(const std::string& data);
349
350         boost::signal<void(const std::string&)> signal_received_string;
351
352     private:
353
354         void slotReceived();
355 }; // eo class SimpleIO2
356
357
358 /**
359  * provides the backend for io handling.
360  *
361  * This (singleton) object provides the management of io events. It collects all wishes for reading/writing
362  * from the io objects and information from the timer events.
363  * It poll()s for the events and distributes them to the objects,
364  *
365  * The class provides the possibility for executing one io cycle (/step) or to run a backend loop.
366  *
367  * @note the Backend class needs to be a friend of IOImplementation since it accesses private members
368  * of IOImplementation while performing the io cycles.
369  */
370 class Backend
371 {
372     public:
373         typedef std::set< int > FdSetType;
374
375     public:
376
377         bool doOneStep(int ms_timeout= -1);
378         void run();
379         void stop();
380
381     protected:
382         Backend();
383         Backend(const Backend& other);
384         ~Backend();
385
386     protected:
387
388         /// the number of currently active backend loops
389         int m_count_active_loops;
390         /// the number of pending stop requests (where each one should exit one active backend loop)
391         int m_count_stop_requests;
392
393         /// the number of currently active backend cycles(/ steps)
394         static int m_count_active_steps;
395
396     public:
397         static Backend* getBackend();
398
399     protected:
400         /// pointer to the active backend (which is delivered by Backend::getBackend)
401         static Backend* g_backend;
402 }; // eo class Backend
403
404
405
406 } // eo namespace AsyncIo
407
408 #endif