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