00001 #ifndef DV_FDSTREAMBUF_H 00002 #define DV_FDSTREAMBUF_H 00003 // $Id: fdstreambuf.h,v 1.32 2008/03/15 10:47:55 dvermeir Exp $ 00004 00005 #include <iostream> 00006 #include <string> 00007 #include <sys/types.h> // for size_t, time_t 00008 #include <dvutil/debug.h> // for size_t, time_t 00009 00010 /** @file 00011 * The Dv::fdstreambuf class provides a streambuf specialization 00012 * that manages a file descriptor (fd) and handles the possibility of 00013 * timeout on input or open by failing an operation if it times out 00014 */ 00015 namespace Dv { 00016 namespace Util { 00017 00018 /** 00019 * A streambuf specialization that manages a file descriptor and handles 00020 * timeouts. It also supports a version that manages two 00021 * filedescriptors, one for input and one for output. 00022 * Derived classes should probably implement @a rread, @a rwrite, 00023 * and possibly @a close, @a iwait and @a owait. 00024 */ 00025 class fdstreambuf: public std::streambuf, public DebugSlave { 00026 public: 00027 enum { INPUT /** index of input file descriptor */ = 0, 00028 OUTPUT /** index of output file descriptor */ = 1}; 00029 /** 00030 * This constructor simply allocates the buffers and stores the 00031 * delay (in millisecs). It uses a single file descriptor 00032 * for both input and output, i.e. @c fd(INPUT) and @c fd(OUTPUT) 00033 * will be identical. 00034 * 00035 * @param fd filedescriptor to be used by this fdstreambuf 00036 * @param inbuf_sz size of input buffer. 00037 * @param outbuf_sz size of output buffer. 00038 * @param delay time, in millisecs, to wait before an open or input 00039 * operation fails, a delay of 0 means ``wait foerver''. 00040 * @param non_blocking whether the underlying filedecriptor is in 00041 * non-blocking (O_NONBLOCK) mode, see fctnl(2). 00042 * Using a non-blocking streambuf prevents some blocking I/O 00043 * operations. E.g. if select(2) indicates that writing is possible 00044 * but the actual number of bytes to write is too large, the write may 00045 * block indefinitely for a blocking Socket. For a non-blocking socket, 00046 * the write(2) will return EAGAIN which will be handled 00047 * appropriately by fdstreambuf. 00048 * @param min_debug_level if a debug_master is connected, logging info 00049 * will only be written if the master's level is at least @a min_debug_level 00050 * @param debug_master from where debug info will be taken 00051 * @see Dv::DebugSlave 00052 * @sa Dv::DebugSlave 00053 * 00054 * The constructor also calls <code>signal(SIGPIPE,SIG_IGN)</code>, 00055 * causing <code>SIGPIPE</code> signals to be ignored. Instead, 00056 * the system should let the I/O operation fail and set errno to 00057 * <code>EPIPE</code>. 00058 */ 00059 explicit fdstreambuf(int fd=-1, size_t inbuf_sz=1024, size_t outbuf_sz=1024, 00060 time_t delay=0, bool non_blocking = false, unsigned int min_debug_level = 5, 00061 Debugable* debug_master = 0); 00062 00063 /** 00064 * This constructor simply allocates the buffers and stores the 00065 * delay (in millisecs). It uses a single file descriptor 00066 * for both input and output, i.e. @c fd(INPUT) and @c fd(OUTPUT) 00067 * will be identical. 00068 * 00069 * The constructor also calls <code>signal(SIGPIPE,SIG_IGN)</code>, 00070 * causing <code>SIGPIPE</code> signals to be ignored. Instead, 00071 * the system should let the I/O operation fail and set errno to 00072 * <code>EPIPE</code>. 00073 * 00074 * Example: 00075 * @code 00076 * int fds[2]; 00077 * if (pipe(fds) < 0) 00078 * return error(ERROR+"pipe() failed",1); 00079 * fdstreambuf fdsbuf(fds, 1024, 1024, 0, false, false, &std::cout); 00080 * std::iostream os(&fdsbuf); 00081 * os << 'a'; os.flush; // writes to pipe 00082 * char c; 00083 * os >> c; // read from pipe 00084 * @endcode 00085 * 00086 * @param fds filedescriptor array to be used by this fdstreambuf. 00087 * The array must contain two file descriptors, @c fds[0] will be 00088 * used for input operations while @c fds[1] will be used for output 00089 * operations. 00090 * @param inbuf_sz size of input buffer. 00091 * @param outbuf_sz size of output buffer. 00092 * @param delay time, in millisecs, to wait before an open or input 00093 * operation fails, a delay of 0 means ``wait foerver''. 00094 * @param non_blocking_input whether the underlying @a INPUT filedecriptor is in 00095 * non-blocking (O_NONBLOCK) mode, see fctnl(2). 00096 * @param non_blocking_output whether the underlying @a OUTPUT filedecriptor is in 00097 * non-blocking (O_NONBLOCK) mode, see fctnl(2). 00098 * Using a non-blocking output file descriptor prevents some blocking I/O 00099 * operations. E.g. if select(2) indicates that writing is possible 00100 * but the actual number of bytes to write is too large, the write may 00101 * block indefinitely for a blocking Socket. For a non-blocking socket, 00102 * the write(2) will return EAGAIN which will be handled 00103 * appropriately by fdstreambuf. 00104 * @param min_debug_level if a debug_master is connected, logging info 00105 * will only be written if the master's level is at least @a min_debug_level 00106 * @param debug_master from where debug info will be taken 00107 * @see Dv::DebugSlave 00108 * @sa Dv::DebugSlave 00109 * 00110 * @warning There is no check whether @c fds[] has the correct size. 00111 */ 00112 explicit fdstreambuf(int fds[], size_t inbuf_sz = 1024, size_t outbuf_sz = 1024, 00113 time_t delay = 0, bool non_blocking_input = false, 00114 bool non_blocking_output = false, unsigned int min_debug_level = 5, 00115 Debugable* debug_master = 0); 00116 /** 00117 * This is already virtual in streambuf. 00118 */ 00119 virtual ~fdstreambuf(); 00120 00121 /** @return true iff the file descriptors for INPUT and OUTPUT are 00122 * identical. 00123 */ 00124 bool shared() const { return shared_; } 00125 00126 /** @return size of input buffer */ 00127 size_t inbuf_sz() const { return inbuf_sz_; } 00128 /** @return size of output buffer */ 00129 size_t outbuf_sz() const { return outbuf_sz_; } 00130 /** 00131 * Return the number of millsecs to wait before an open or input operation 00132 * fails. A value of 0 means wait forever. 00133 * 00134 * @return The current delay value. 00135 */ 00136 time_t delay() const { return delay_; } 00137 00138 /** 00139 * Set delay (0 means infinite delay). 00140 * 00141 * @param d delay in millisecs, 0 means ``wait forever''. 00142 */ 00143 void delay(time_t d) { delay_ = d; } 00144 00145 /** 00146 * Return the blocking status for a file descriptor of this fdstreambuf. 00147 * 00148 * @param which INPUT or OUTPUT 00149 * @return true iff the constructor was called with non_blocking or 00150 * set_non_blocking() was called before. 00151 */ 00152 bool non_blocking(size_t which = INPUT) const { return non_blocking_[index(which)]; } 00153 00154 /** 00155 * Set non-blocking I/O for a file descriptor of this fdstreambuf. 00156 * 00157 * @param which INPUT or OUTPUT 00158 * @return 0 upon success, -1 else in which case error() will 00159 * reflect the system errno. 00160 * @see fcntl(2) 00161 */ 00162 int set_non_blocking(size_t which = INPUT); 00163 00164 /** 00165 * Return file descriptor underlying this fdstreambuf object. 00166 * 00167 * @param which INPUT or OUTPUT 00168 * @return The current value for the underlying file descriptor. 00169 */ 00170 int fd(size_t which = INPUT) const { return fds_[index(which)]; } 00171 00172 /** 00173 * Set the underlying file descriptor. The previous descriptor, if 00174 * valid, is closed. 00175 * 00176 * @param i New file descriptor. 00177 * @param non_blocking Whether I/O should be non-blocking. 00178 * @param which File descriptor to set: INPUT or OUTPUT 00179 * @return true iff close() of the previous valid file descriptor 00180 * succeeded 00181 * @see fdstreambuf::close() 00182 */ 00183 bool fd(int i, bool non_blocking = false, size_t which = INPUT); 00184 00185 /** 00186 * Close the underlying file descriptor. 00187 * 00188 * @return false iff close() of the underlying valid file descriptor 00189 * failed. 00190 */ 00191 virtual bool close(size_t which = INPUT); 00192 00193 /** 00194 * Return true iff last I/O operation timed out. 00195 * 00196 * @return true iff the last I/O operation timed out or 00197 * timedout(true) was called since the last I/O operation. 00198 */ 00199 bool timedout() const { return timedout_; } 00200 00201 /** 00202 * Set timedout() flag. This flag can only be cleared explicitly by 00203 * fdstreambuf::timedout(false) or by fdstreambuf::fd(int). 00204 * 00205 * @param timed_out New value for timedout(). 00206 * @return true iff timedout status actually changed. It will 00207 * return false, e.g. if the argument is false but the 00208 * previous timedout status was not true. 00209 */ 00210 bool timedout(bool timed_out) const; 00211 00212 /** 00213 * Return last relevant ::errno as set by the system. 00214 * 00215 * @return The last relevant errno as set by the system. 00216 */ 00217 int error() const { return errno_; } 00218 00219 /** 00220 * Return ::strerror(error()), a string representation of error(). 00221 * 00222 * @return A string representation of error(). 00223 */ 00224 std::string strerror() const; 00225 00226 /** 00227 * Check whether input or output on a file descriptor would block. 00228 * 00229 * @param fd file descriptor to check, none if -1 00230 * @param delay time (in millisecs) we are prepared to wait. If 00231 * <code>0</code>, <code>fdwait()</code> may block indefinitely. 00232 * @param syserrno will contain system's errno if return -1 00233 * @param output false if fd is checked for input 00234 * @param osp if not 0, pointer to Dv::ostream_ptr on which trace/debug output 00235 * will be written 00236 * @return <code>1</code> if input/output is available; <code>0</code> 00237 * if a timeout occurred (in which case syserrno=ETIMEOUT) 00238 * and a value <code><0</code> if another error occurred, in which case 00239 * syserrno set to errno. 00240 * @sa Dv::ostream_ptr 00241 */ 00242 static int fdwait(int fd, time_t delay, int& syserrno, bool output=false, 00243 ostream_ptr* osp = 0); 00244 00245 /** 00246 * Override iostream::sync(), i.e. force all pending output to 00247 * be written using fdstreambuf::rwrite(). 00248 * 00249 * @return 0 if ok, -1 else. 00250 */ 00251 virtual int sync(); 00252 00253 /** Set the number bytes read so far. 00254 * The constructors set this number to 0. 00255 * @param n new value of @c n_read 00256 * @return the old value of @c n_read 00257 * @see Dv::Util::fdstreambuf::n_read 00258 */ 00259 unsigned long long set_n_read(unsigned long long n = 0); 00260 00261 /** The number of bytes read so far. 00262 * @return number of bytes read so far or since the last 00263 * call to Dv:::Util::set_n_read 00264 * @see Dv::Util::fdstreambuf::set_n_read 00265 */ 00266 unsigned long long n_read() const { return n_read_; } 00267 00268 /** Set the number bytes written so far. 00269 * The constructors set this number to 0. 00270 * @param n new value of @c n_written 00271 * @return the old value of @c n_written 00272 * @see Dv::Util::fdstreambuf::n_written 00273 */ 00274 unsigned long long set_n_written(unsigned long long n = 0); 00275 00276 /** The number of bytes written so far. 00277 * @return number of bytes written so far or since the last 00278 * call to Dv:::Util::set_n_written 00279 * @see Dv::Util::fdstreambuf::set_n_written 00280 */ 00281 unsigned long long n_written() const { return n_written_; } 00282 00283 /** Debug: write info on fdstreambuf on output stream. 00284 * @param os write dump to this stream 00285 * @return os 00286 */ 00287 std::ostream& dump(std::ostream& os) const; 00288 00289 protected: 00290 /** 00291 * Override iostream::underflow(), i.e. attempt to fill the input 00292 * buffer using fdstreambuf::rread(). 00293 * 00294 * @return next input char or EOF. 00295 */ 00296 virtual int underflow(); 00297 00298 /** 00299 * Override iostream::overflow(). May call fdstreambuf::sync(). 00300 * 00301 * @return c if the character was succeffuly written or EOF. 00302 */ 00303 virtual int overflow(int c); 00304 00305 /** 00306 * Wait for I/O to become available. Wait for output or input, 00307 * depending on the value of the parameter. Sets error() 00308 * appropriately if return value is not 1. 00309 * 00310 * @param output Wait for output to be available if 00311 * @return 1 if input is available, 0 if a timeout occurred; -1 00312 * indicates an error condition (e.g. underlying fd not set). 00313 * @see fdwait 00314 */ 00315 int fdwait(bool output) const; 00316 00317 /** 00318 * Wait for I/O to become available. Wait for output or input, 00319 * depending on the value of the parameter. 00320 * 00321 * @param output Wait for output to be available if 00322 * @param syserrno System errorno (output variable). 00323 * @return 1 if input is available, 0 if a timeout occurred; -1 00324 * indicates an error condition (e.g. underlying fd not set). 00325 * @see fdwait 00326 */ 00327 int fdwait(bool output, int& syserrno) const; 00328 00329 /** 00330 * Wait for input to become available. Equivalent to fdwait(false). 00331 * This is a virtual function because for some transports, 00332 * iwait() may need to consult other data structures. E.g. 00333 * when using openssl, iwait should call SSL_pending before 00334 * fdstreambuf::iwait. This is the function actually used in 00335 * the implementation of fdstreambuf::read. 00336 * 00337 * @return 1 if input is available, 0 if a timeout occurred; -1 00338 * indicates an error condition (e.g. underlying fd not set). 00339 */ 00340 virtual int iwait() const; 00341 00342 /** 00343 * Wait for output to become available. Equivalent to fdwait(true). 00344 * 00345 * @return 1 if input is available, 0 if a timeout occurred; -1 00346 * indicates an error condition (e.g. underlying fd not set). 00347 */ 00348 virtual int owait() const { return fdwait(true); } 00349 00350 /** 00351 * Attempt an input operation on the @a INPUT file descriptor. 00352 * 00353 * @param buf Buffer where characters read will be put. 00354 * @param buf_sz Number of characters to read. 00355 * @return number of chars read, 0 on EOF, -1 if timeout, 00356 * -2 if other error. 00357 * 00358 * On timeout, error() is set to ETIMEDOUT. 00359 * Input operations are retried if they were interrupted. 00360 * 00361 * @see error() 00362 */ 00363 virtual int read(char* buf,size_t buf_sz); 00364 00365 /** 00366 * Attempt an output operation on the @a OUTPUT file descriptor. 00367 * @param buf Buffer containing characters to write. 00368 * @param buf_sz Number of characters to write from buf. 00369 * @return number of chars written, 0 on EOF, -1 if timeout, 00370 * -2 if other error. 00371 * On timeout, error() is set to ETIMEDOUT. 00372 * Output operations are retried if they were interrupted. 00373 * 00374 * @see error() 00375 */ 00376 virtual int write(char* buf,size_t buf_sz); 00377 00378 /** 00379 * Low level read function, default is ::read(fd(INPUT), buf, len); 00380 * may set error(). 00381 * Derived classes can override this function. 00382 * 00383 * @param buf Buffer where characters read will be put. 00384 * @param len Number of characters to read. 00385 * @return number of chars read, 0 on EOF, -1 on error. 00386 * 00387 * @see error() 00388 */ 00389 virtual int rread(char* buf,size_t len); 00390 00391 /** 00392 * Low level write function, default is ::write(fd(OUTPUT), buf, len); may 00393 * set error(). 00394 * Derived classes can override this function. 00395 * 00396 * @param buf Buffer containing characters to write. 00397 * @param len Number of characters to write from buf. 00398 * @return number of chars read, 0 means no chars were written. 00399 * On error, -1 is returned. 00400 * 00401 * @see error() 00402 */ 00403 virtual int rwrite(char* buf,size_t len); 00404 00405 /** 00406 * Translate ios::openmode flags to open(2) flags like O_RDWR etc. 00407 * 00408 * @param mode Stream open mode. 00409 * @return A combination of O_RDWR, O_CREAT, O_APPEND, O_WRONLY, 00410 * O_TRUNC, O_RDONLY. 00411 * 00412 * Currently, the function understands combinations with 00413 * ios::in, ios::out, ios::app, ios::trunc. 00414 */ 00415 static int flags(std::ios::openmode mode); 00416 00417 /** 00418 * Set error status of fdstreambuf. 00419 * 00420 * @param e new error code. 00421 * 00422 * @see fdstreambuf::error(). 00423 */ 00424 void error(int e) const; 00425 00426 private: 00427 fdstreambuf(const fdstreambuf&); // forbidden 00428 fdstreambuf& operator=(const fdstreambuf&); // forbidden 00429 00430 /** Utility that converts any parameter different from INPUT 00431 * to OUTPUT. 00432 * @param which size_t, normally @a INPUT or @a OUTPUT 00433 * @return @a INPUT if paramater is @a INPUT 00434 * @return @a OUTPUT if parameter is not @a INPUT 00435 */ 00436 size_t index(size_t which) const { return (which == INPUT ? INPUT : OUTPUT); } 00437 00438 /** 00439 * Underlying file descriptors: <code>fds_[INPUT]</code> is used for input, 00440 * <code>fds_[OUTPUT]</code> is used for output. It is possible that 00441 * <code>fds_[INPUT] == fds_[OUTPUT]</code>. A negative value 00442 * indicates no file descriptor available. 00443 */ 00444 int fds_[2]; 00445 00446 /** 00447 * The number of millsecs to wait before an open or input operation 00448 * fails. A value of 0 means wait forever. 00449 */ 00450 time_t delay_; 00451 00452 /** 00453 * Whether <code>fds_[i]</code> is non-blocking. 00454 */ 00455 bool non_blocking_[2]; 00456 00457 /** 00458 * Size of internal input buffer. 00459 */ 00460 size_t inbuf_sz_; 00461 /** 00462 * Size of internal output buffer. 00463 */ 00464 size_t outbuf_sz_; 00465 /** 00466 * Input buffer. 00467 */ 00468 char* inbuf_; 00469 /** 00470 * Output buffer. 00471 */ 00472 char* outbuf_; 00473 /** 00474 * Error status. A value of 0 means ok. Usually, the value of the 00475 * last @c ::errno as set by the system. 00476 */ 00477 mutable int errno_; 00478 /** 00479 * Did the last operation time out? Set if @c ::errno is ETIMEDOUT. 00480 * @sa timedout 00481 */ 00482 mutable bool timedout_; 00483 /** 00484 * Shared is true iff fds_[INPUT] == fds_[OUTPUT] should be 00485 * maintained. 00486 */ 00487 bool shared_; 00488 00489 /** Number of bytes read so far. Can be set by the user as well. */ 00490 unsigned long long n_read_; 00491 /** Number of bytes written so far. Can be set by the user as well. */ 00492 unsigned long long n_written_; 00493 00494 }; 00495 } 00496 } 00497 #endif
dvutil-1.0.10 | [ 5 December, 2009] |