Migrate libasyncio from boost.signal to signals2 (#8756)
[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/signals2.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 descriptor 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::signals2::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::signals2::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();                //lint !e1509  // boost::signals2::signals::trackable is not virtual
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         virtual std::string getInput() const;
236         virtual std::string getInputClear();
237         virtual bool inputAvailable() const;
238         virtual std::string::size_type shortenInput(std::string::size_type len);
239         virtual std::string getline(char delim='\n');
240
241     protected:
242
243         void addFilter(FilterBasePtr filter);
244         void removeFilter(FilterBasePtr);
245
246
247         void lowSend(const std::string& data);
248
249         std::string::size_type getOutputBufferSize() const { return m_output_buffer.size(); }
250
251         void setWriteFd(int fd);
252         void setReadFd(int fd);
253
254         inline int readFd() const
255         {
256             return m_read_fd;
257         }
258
259         inline int writeFd() const
260         {
261             return m_write_fd;
262         }
263
264         inline bool isMarkedForReading() const { return m_marked_for_reading; }
265         inline bool isMarkedForWriting() const { return m_marked_for_writing; }
266
267
268     protected:
269         virtual void doRead();
270         virtual void doWrite();
271
272         void resetReadMark()  { m_marked_for_reading= false; }
273         void resetWriteMark() { m_marked_for_writing= false; }
274
275         void injectIncomingData(FilterBasePtr from_filter, const std::string& _data);
276         void injectOutgoingData(FilterBasePtr from_filter, const std::string& _data);
277
278     protected:
279         /// last error number
280         int m_errno;
281         /// the input buffer (i.e. the data read from @a m_read_fd)
282         std::string m_input_buffer;
283
284         /// the chain of filter which are applied to the data received are the data which should be send.
285         FilterChain m_filter_chain;
286
287         /// signal which is fired when end of file is detected
288         SignalType m_signal_eof;
289         /// signal which is fired when write is no longer possible
290         SignalType m_signal_not_writable;
291         /// signal which is fired when new data was read
292         SignalType m_signal_read;
293         /// signal which is fired when data was written
294         SignalType m_signal_write;
295
296         /// end of file (on @a m_read_fd) detected (used additionally when m_read_fd is valid)
297         bool m_eof;
298
299         /// unable-to-write (on @a m_write_fd) detected (used additionally when m_write_fd is valid)
300         bool m_not_writable;
301
302     private:
303         /// the file descriptor to read from (-1 if none is given)
304         int m_read_fd;
305         /// the file descriptor to write to (-1 if none is given)
306         int m_write_fd;
307         /// output buffer; contains the data which needs to be written.
308         std::string m_output_buffer;
309
310     private:
311         /// @a true when data is available to be read
312         bool m_marked_for_reading;
313         /// @a true when data can be written
314         bool m_marked_for_writing;
315
316 }; // eo class IOImplementation
317
318
319
320 /**
321  * same as IOImplementation, but makes fd access functions public.
322  */
323 class IOImplementation2 : public IOImplementation
324 {
325         typedef IOImplementation inherited;
326     public:
327         IOImplementation2(int read_fd=-1, int write_fd=-1) : inherited(read_fd, write_fd) {}
328
329         void setWriteFd(int fd) { inherited::setWriteFd(fd); }
330         void setReadFd(int fd)  { inherited::setReadFd(fd); }
331
332         int readFd() const { return inherited::readFd(); }
333         int writeFd() const { return inherited::writeFd(); }
334
335 }; // eo class IOImplementation2
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 SimpleIO : public IOImplementation
344 {
345         typedef IOImplementation inherited;
346     public:
347         SimpleIO(int read_fd=-1, int write_fd=-1);
348         virtual ~SimpleIO();
349
350         void sendString(const std::string& data);
351
352         boost::signals2::signal<void(const std::string&)> signal_received_string;
353
354     private:
355
356         void slotReceived();
357 }; // eo class SimpleIO
358
359
360 /**
361  * provides sending data and receiving data via a signal.
362  *
363  * @note the received data is passed as parameter to the signal and no longer stored in the received buffer.
364  */
365 class SimpleIO2 : public IOImplementation2
366 {
367         typedef IOImplementation2 inherited;
368     public:
369         SimpleIO2(int read_fd=-1, int write_fd=-1);
370         virtual ~SimpleIO2();
371
372         void sendString(const std::string& data);
373
374         boost::signals2::signal<void(const std::string&)> signal_received_string;
375
376     private:
377
378         void slotReceived();
379 }; // eo class SimpleIO2
380
381
382 /**
383  * provides the backend for io handling.
384  *
385  * This (singleton) object provides the management of io events. It collects all wishes for reading/writing
386  * from the io objects and information from the timer events.
387  * It poll()s for the events and distributes them to the objects,
388  *
389  * The class provides the possibility for executing one io cycle (/step) or to run a backend loop.
390  *
391  * @note the Backend class needs to be a friend of IOImplementation since it accesses private members
392  * of IOImplementation while performing the io cycles.
393  */
394 class Backend
395 {
396     public:
397         typedef std::set< int > FdSetType;
398
399     public:
400
401         bool doOneStep(int ms_timeout= -1);
402         void run();
403         void stop();
404
405     protected:
406         Backend();
407         Backend(const Backend& other);
408         ~Backend();
409
410     protected:
411
412         /// the number of currently active backend loops
413         int m_count_active_loops;
414         /// the number of pending stop requests (where each one should exit one active backend loop)
415         int m_count_stop_requests;
416
417         /// the number of currently active backend cycles(/ steps)
418         static int m_count_active_steps;
419
420     public:
421         static Backend* getBackend();
422
423     protected:
424         /// pointer to the active backend (which is delivered by Backend::getBackend)
425         static Backend* g_backend;
426 }; // eo class Backend
427
428
429
430 } // eo namespace AsyncIo
431
432 #endif