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