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