unconditionally use namespace I2n; include signalfunc from our utils
[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
RP
41
42#include <boost/signal.hpp>
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 *
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 */
206class IOImplementation
207: public boost::signals::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
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 */
317class 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 */
337class 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 */
359class 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 */
388class 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
42b7c46d 424} // eo namespace AsyncIo
5c8a3d40
RP
425
426#endif