Migrate libasyncio from boost.signal to signals2 (#8756)
[libasyncio] / asyncio / async_io.hpp
CommitLineData
8c15b8c7
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
20/**
5c8a3d40
RP
21 * @file
22 * @brief simple basic IO handling.
23 *
24 * @copyright © Copyright 2007-2008 by Intra2net AG
5c8a3d40
RP
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
42b7c46d
RP
31#ifndef __ASYNC_IO_HPP__
32#define __ASYNC_IO_HPP__
5c8a3d40
RP
33
34#include <string>
35#include <list>
36#include <set>
37
fd6ea89e 38#include <asyncio_config.hpp>
aba4c34d 39
fd6ea89e 40#include <asyncio_utils.hpp>
5c8a3d40 41
983acc1f 42#include <boost/signals2.hpp>
5c8a3d40
RP
43#include <boost/shared_ptr.hpp>
44
45
42b7c46d 46namespace AsyncIo
5c8a3d40
RP
47{
48
42b7c46d 49using namespace I2n;
74786da6 50
aba4c34d 51using Utils::MilliTime;
5c8a3d40
RP
52
53/*
54 * forward declarations
55 */
56class Backend;
57class IOImplementation;
58
59/*
60 * end of forward declarations
61 */
62
63
64/**
65 * direction for io operations.
66 */
67struct 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
5c8a3d40
RP
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 */
90class TimerBase
91{
92 friend class Backend;
93 public:
94 TimerBase();
95 virtual ~TimerBase();
96
74786da6 97 bool active() const { return m_active; }
5c8a3d40
RP
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 */
135class FilterBase
fd6ea89e 136: virtual public Utils::SharedBase
5c8a3d40
RP
137{
138 friend class IOImplementation;
139 public:
140 typedef boost::shared_ptr< FilterBase > PtrType;
141 public:
142 FilterBase();
9f5d794e 143 virtual ~FilterBase() { m_io = NULL; };
5c8a3d40
RP
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
163typedef FilterBase::PtrType FilterBasePtr;
164
165
166/**
167 * identity filter; does nothing with the data (in other words: it's useless ;-) ).
168 */
169class 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 */
182class 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 *
6729e46a 193 * provides the functionality to read from a file descriptor and write to a file descriptor (which can be
5c8a3d40
RP
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 */
206class IOImplementation
983acc1f 207: public boost::signals2::trackable
fd6ea89e 208, virtual public Utils::SharedBase
5c8a3d40
RP
209{
210 friend class Backend;
211 friend class FilterBase;
212
213 public:
214
215 typedef std::list< FilterBasePtr > FilterChain;
216
983acc1f 217 typedef boost::signals2::signal< void() > SignalType;
5c8a3d40
RP
218
219 typedef boost::shared_ptr< IOImplementation > PtrType;
220
221 public:
222 IOImplementation(int read_fd=-1, int write_fd=-1);
983acc1f 223 virtual ~IOImplementation(); //lint !e1509 // boost::signals2::signals::trackable is not virtual
5c8a3d40
RP
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
b9c8a8e5
GE
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);
054f19f4 239 virtual std::string getline(char delim='\n');
b9c8a8e5 240
5c8a3d40
RP
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 */
323class 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 */
343class 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
983acc1f 352 boost::signals2::signal<void(const std::string&)> signal_received_string;
5c8a3d40
RP
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 */
365class 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
983acc1f 374 boost::signals2::signal<void(const std::string&)> signal_received_string;
5c8a3d40
RP
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 */
394class 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
42b7c46d 430} // eo namespace AsyncIo
5c8a3d40
RP
431
432#endif