updated to use new modules (more independance to libi2ncommon)
[libasyncio] / asyncio / async_io.hpp
CommitLineData
5c8a3d40
RP
1/**
2 * @file
3 * @brief simple basic IO handling.
4 *
5 * @copyright © Copyright 2007-2008 by Intra2net AG
42b7c46d 6 * @license LGPL
5c8a3d40
RP
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
42b7c46d
RP
14#ifndef __ASYNC_IO_HPP__
15#define __ASYNC_IO_HPP__
5c8a3d40
RP
16
17#include <string>
18#include <list>
19#include <set>
20
fd6ea89e 21#include <asyncio_config.hpp>
aba4c34d 22
fd6ea89e 23#include <asyncio_utils.hpp>
5c8a3d40
RP
24
25#include <boost/signal.hpp>
26#include <boost/shared_ptr.hpp>
27
28
42b7c46d 29namespace AsyncIo
5c8a3d40
RP
30{
31
fd6ea89e 32#ifdef HAVE_LIBI2NCOMMON
42b7c46d 33using namespace I2n;
fd6ea89e 34#endif
aba4c34d 35using Utils::MilliTime;
5c8a3d40
RP
36
37/*
38 * forward declarations
39 */
40class Backend;
41class IOImplementation;
42
43/*
44 * end of forward declarations
45 */
46
47
48/**
49 * direction for io operations.
50 */
51struct 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
5c8a3d40
RP
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 */
74class 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 */
119class FilterBase
fd6ea89e 120: virtual public Utils::SharedBase
5c8a3d40
RP
121{
122 friend class IOImplementation;
123 public:
124 typedef boost::shared_ptr< FilterBase > PtrType;
125 public:
126 FilterBase();
9f5d794e 127 virtual ~FilterBase() { m_io = NULL; };
5c8a3d40
RP
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
147typedef FilterBase::PtrType FilterBasePtr;
148
149
150/**
151 * identity filter; does nothing with the data (in other words: it's useless ;-) ).
152 */
153class 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 */
166class 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 */
190class IOImplementation
191: public boost::signals::trackable
fd6ea89e 192, virtual public Utils::SharedBase
5c8a3d40
RP
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 */
301class 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 */
321class 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 */
343class 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 */
372class 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
42b7c46d 408} // eo namespace AsyncIo
5c8a3d40
RP
409
410#endif