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