Download this file

iodevice.h    402 lines (323 with data), 11.3 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
/*-*-mode:c++;c-basic-offset:2-*-*/
/* --------------------------------------------------------------------
* Filename:
* src/iodevice.h
*
* Description:
* Declaration of the IODevice class.
* --------------------------------------------------------------------
* Copyright 2002, 2003 Andreas Aardal Hanssen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
* --------------------------------------------------------------------
*/
#ifndef iodevice_h_included
#define iodevice_h_included
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "convert.h" // BincStream
#include <string>
#include <unistd.h> // ::write
namespace Binc {
/*!
\class IODevice
\brief The IODevice class provides a framework for reading and
writing to device.
Implement new devices by inheriting this class and overloading all
virtual methods.
service() returns the service that the specific device is used
for. Two values are "log" and "client".
\sa IOFactory, MultilogDevice, SyslogDevice, StdIODevice, SSLDevice
*/
class IODevice {
public:
/*!
Standard options for an IODevice.
*/
enum Flags {
None = 0,
FlushesOnEndl = 1 << 0,
HasInputLimit = 1 << 1,
HasOutputLimit = 1 << 2,
IsEnabled = 1 << 3,
HasTimeout = 1 << 4
};
/*!
Errors from when an operation returned false.
*/
enum Error {
Unknown,
Timeout
};
/*!
Constructs an invalid IODevice.
Instances of IODevice perform no operations, and all boolean
functions always return false. This constructor is only useful
if called from a subclass that reimplements all virtual methods.
*/
IODevice(int f = 0);
/*!
Destructs an IODevice; does nothing.
*/
virtual ~IODevice(void);
/*!
Clears all data in the input and output buffers.
*/
void clear(void);
/*!
Sets one or more flags.
\param f A bitwise OR of flags from the Flags enum.
*/
void setFlags(unsigned int f);
/*!
Clears one or more flags.
\param f A bitwise OR of flags from the Flags enum.
*/
void clearFlags(unsigned int f);
/*!
Sets the maximum allowed input buffer size. If this size is
non-zero and exceeded, reading from the device will fail. This
functionality is used to prevent clients from forcing this class
to consume so much memory that the program crashes.
Setting the max input buffer size to 0 disables the input size
limit.
\param max The maximum input buffer size in bytes.
*/
void setMaxInputBufferSize(unsigned int max);
/*!
Sets the maximum allowed output buffer size. If this size is
non-zero and exceeded, flush() is called implicitly.
Setting the max output buffer size to 0 disables the output size
limit. This is generally discouraged.
As a contrast to setMaxInputBufferSize(), this function is used
to bundle up consequent write calls, allowing more efficient use
of the underlying device as larger blocks of data are written at
a time.
\param max The maximum output buffer size in bytes.
*/
void setMaxOutputBufferSize(unsigned int max);
/*!
Sets the device's internal timeout in seconds. This timeout is
used both when waiting for data to read and for waiting for the
ability to write.
If this timeout is exceeded, the read or write function that
triggered the timeout will fail.
Setting the timeout to 0 disables the timeout.
\param t The timeout in seconds.
\sa getTimeout()
*/
void setTimeout(unsigned int t);
/*!
Returns the timeout in seconds, or 0 if there is no timeout.
\sa setTimeout()
*/
unsigned int getTimeout(void) const;
enum LogLevel {
ErrorLevel,
InfoLevel,
WarningLevel,
DebugLevel
};
/*!
Sets the output level for the following write operations on this
device.
The output level is a number which gives the following write
operations a priority. You can use setOutputLevelLimit() to
filter the write operations valid for different operating modes.
This enables you to have certain write operations ignored.
For instance, if the output level is set to 0, then "Hello" is
written, and the output level is set to 1, followed by writing
"Daisy", the output level limit value will decive wether only
"Hello" is written, or if also "Daisy" is written.
A low value of the level gives higher priority, and a high level
will give low priority. The default value is 0, and write
operations that are done with output level 0 are never ignored.
\param level The output level
\sa getOutputLevel(), setOutputLevelLimit()
*/
void setOutputLevel(LogLevel level);
/*!
Returns the current output level.
\sa setOutputLevel()
*/
LogLevel getOutputLevel(void) const;
/*!
Sets the current output level limit. Write operations with a
level higher than the output level limit are ignored.
\param level The output level limit
\sa setOutputLevel()
*/
void setOutputLevelLimit(LogLevel level);
/*!
Returns the current output level limit.
\sa setOutputLevelLimit()
*/
LogLevel getOutputLevelLimit(void) const;
/*!
Returns the number of bytes that have been read from this device
since it was created.
*/
unsigned int getReadCount(void) const;
/*!
Returns the number of bytes that have been written to this
device since it was created.
*/
unsigned int getWriteCount(void) const;
/*!
Calling this function enables the built-in protocol dumping feature in
the device. All input and output to this device will be dumped to a file
in /tmp.
*/
void enableProtocolDumping(void);
/*!
Writes data to the device. Depending on the value of the max
output buffer size, the data may not be written immediately.
\sa setMaxOutputBufferSize()
*/
template <class T> IODevice &operator <<(const T &source);
/*!
Writes data to the device. This function specializes on standard
ostream derivates, such as std::endl.
*/
IODevice &operator <<(std::ostream &(*source)(std::ostream &));
/*!
Returns true if data can be read from the device; otherwise
returns false.
*/
virtual bool canRead(void) const;
/*!
Reads data from the device, and stores this in a string. Returns
true on success; otherwise returns false.
\param dest The incoming data is stored in this string.
\param max No more than this number of bytes is read from the
device.
*/
bool readStr(std::string *dest, unsigned int max = 0);
/*!
Reads exactly one byte from the device and stores this in a
char. Returns true on success; otherwise returns false.
\param dest The incoming byte is stored in this char.
*/
bool readChar(char *dest = 0);
/*!
FIXME: add docs
*/
void unreadChar(char c);
/*!
FIXME: add docs
*/
void unreadStr(const std::string &s);
/*!
Reads characters from the device, until and including one
certain character is found. All read characters are discarded.
This function can be used to skip to the beginning of a line,
with the terminating character being '\n'.
\param The certain character.
*/
bool skipTo(char c);
/*!
Flushes the output buffer. Writes all data in the output buffer
to the device.
*/
bool flush(void);
/*!
Returns the type of error that most recently occurred.
*/
Error getLastError(void) const;
/*!
Returns a human readable description of the error that most
recently occurred. If no known error has occurred, this method
returns "Unknown error".
*/
std::string getLastErrorString(void) const;
/*!
Returns the type of service provided by this device. Two valid
return values are "client" and "log".
*/
virtual std::string service(void) const;
protected:
/*!
Waits until data can be written to the device. If the timeout is
0, this function waits indefinitely. Otherwise, it waits until
the timeout has expired.
If this function returns true, data can be written to the
device; otherwise, getLastError() must be checked to determine
whether a timeout occurred or whether an error with the device
prevents further writing.
*/
virtual bool waitForWrite(void) const;
/*!
Waits until data can be read from the device.
\sa waitForWrite()
*/
virtual bool waitForRead(void) const;
/*!
Types of results from a write.
*/
enum WriteResult {
WriteWait = 0,
WriteDone = 1 << 0,
WriteError = 1 << 1
};
/*!
Writes as much data as possible to the device. If some but not
all data was written, returns WriteWait. If all data was
written, returns WriteDone. If an error occurred, returns
WriteError.
*/
virtual WriteResult write(void);
/*!
Reads data from the device, and stores it in the input buffer.
Returns true on success; otherwise returns false.
This method will fail if there is no more data available, if a
timeout occurred or if an error with the device prevents more
data from being read.
The number of bytes read from the device is undefined.
*/
virtual bool fillInputBuffer(void);
BincStream inputBuffer;
BincStream outputBuffer;
protected:
unsigned int flags;
unsigned int maxInputBufferSize;
unsigned int maxOutputBufferSize;
unsigned int timeout;
unsigned int readCount;
unsigned int writeCount;
LogLevel outputLevel;
LogLevel outputLevelLimit;
mutable Error error;
mutable std::string errorString;
int dumpfd;
};
//----------------------------------------------------------------------
template <class T> IODevice &IODevice::operator <<(const T &source)
{
if ((flags & IsEnabled) && outputLevel <= outputLevelLimit) {
outputBuffer << source;
if (dumpfd) {
BincStream ss;
ss << source;
::write(dumpfd, ss.str().c_str(), ss.getSize());
}
if (flags & HasInputLimit)
if (outputBuffer.getSize() > maxOutputBufferSize)
flush();
}
return *this;
}
}
#endif