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