1 message in net.sourceforge.lists.courier-users[courier-users] [PATCH] read/write ti...
FromSent OnAttachments
Johnny C. LamOct 23, 2007 3:11 pm 
Actions with this message:
Paste this link in email or IM:
Paste this link in email or IM:
Atom feed for this thread
Paste this URL into your reader:
Subject:[courier-users] [PATCH] read/write timeouts for afxiopipestream objectsActions...
From:Johnny C. Lam (jlam@buildlink.org)
Date:Oct 23, 2007 3:11:53 pm
List:net.sourceforge.lists.courier-users

The following patch against HEAD allows one to specify timeouts for the reads and writes performed by afxiopipestream objects. I use this to catch long delays when reading or writing data from an afxiopipestream object bound to a socket file descriptor. The default behavior is the current behavior with "infinite" (actually system-specific) timeouts. The changes to afx.h are source-compatible, so existing code that uses afxiopipestream objects does not need to be changed.

As an aside, the afxiopipestream class is very nice to use. It allows binding a stream to a file descriptor and manages the buffering automatically. The only extra thing I needed was a way to time-out the reads and writes to the file descriptor, which the attached patch provides.

Cheers,

-- Johnny C. Lam

diff -ur afx/afx.h /home/jlam/milter/afx/afx.h --- afx/afx.h Mon Jul 30 00:25:53 2007 +++ /home/jlam/milter/afx/afx.h Tue Oct 23 22:02:51 2007 @@ -8,6 +8,9 @@

#include "afx/config.h"

+#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif #if HAVE_UNISTD_H #include <unistd.h> #endif @@ -26,12 +29,15 @@ class afxpipestreambuf : public std::streambuf { int fd; char buffer[8192]; + time_t read_timeout; + time_t write_timeout;

public: + enum timeout_value { TIMEOUT_INF = 0 };

std::ios *iosp;

- afxpipestreambuf(int); + afxpipestreambuf(int, time_t = TIMEOUT_INF, time_t = TIMEOUT_INF); ~afxpipestreambuf(); void close(); void seekg(std::streampos); @@ -47,7 +53,9 @@ class afxipipestream : public std::istream { afxpipestreambuf fd_; public: - afxipipestream(int = -1); + enum timeout_value { TIMEOUT_INF = afxpipestreambuf::TIMEOUT_INF }; + + afxipipestream(int = -1, time_t = TIMEOUT_INF); ~afxipipestream();

void close() { fd_.close(); } @@ -61,7 +69,9 @@ class afxopipestream: public std::ostream { afxpipestreambuf fd_; public: - afxopipestream(int = -1); + enum timeout_value { TIMEOUT_INF = afxpipestreambuf::TIMEOUT_INF }; + + afxopipestream(int = -1, time_t = TIMEOUT_INF); ~afxopipestream(); void close() { fd_.close(); } void seekg(std::streampos p) { fd_.seekg(p); } @@ -74,7 +84,9 @@ class afxiopipestream: public std::iostream { afxpipestreambuf fd_; public: - afxiopipestream(int = -1); + enum timeout_value { TIMEOUT_INF = afxpipestreambuf::TIMEOUT_INF }; + + afxiopipestream(int = -1, time_t = TIMEOUT_INF, time_t = TIMEOUT_INF); ~afxiopipestream(); void close() { fd_.close(); } void seekg(std::streampos p) { fd_.seekg(p); } diff -ur afx/afxpipe.C /home/jlam/milter/afx/afxpipe.C --- afx/afxpipe.C Sun Aug 5 20:00:33 2001 +++ /home/jlam/milter/afx/afxpipe.C Tue Oct 23 22:06:57 2007 @@ -4,10 +4,68 @@ */

#include "afx.h" +#include <errno.h> +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif

static const char rcsid[]="$Id: afxpipe.C,v 2.1 2001/08/05 20:00:33 mrsam Exp
$";

-afxpipestreambuf::afxpipestreambuf(int f) : fd(f), iosp(0) +static int fd_timeout(int fd, time_t timeout, int read) +{ + fd_set readfds, writefds; + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + if (read) + FD_SET(fd, &readfds); + else + FD_SET(fd, &writefds); + + struct timeval tv, *tvp=0; + + if (timeout != afxpipestreambuf::TIMEOUT_INF) + { + tv.tv_sec=timeout; + tv.tv_usec=0; + tvp=&tv; + } + + for (;;) + { + int rv=select(fd+1, &readfds, &writefds, 0, tvp); + + if (rv > 0) + { + if (read) + { + if (!FD_ISSET(fd, &readfds)) + return (-1); + } + else + { + if (!FD_ISSET(fd, &writefds)) + return (-1); + } + return (0); + } + else if (rv == 0) + return (-1); + else if (rv < 0) + { + if (errno == EINTR) + continue; + else + return (-1); + } + } +} + +afxpipestreambuf::afxpipestreambuf(int f, time_t rto, time_t wto) + : fd(f), read_timeout(rto), write_timeout(wto), iosp(0) { }

@@ -66,6 +124,10 @@

while (p < e) { + if (write_timeout != TIMEOUT_INF && + fd_timeout(fd, write_timeout, 0) < 0) + return (-1); + int n=::write(fd, p, e-p);

if (n <= 0 && iosp) @@ -86,7 +148,9 @@ int n;

if (fd < 0) - return (-1); + return (-1); + if (read_timeout != TIMEOUT_INF && fd_timeout(fd, read_timeout, 1) < 0) + return (-1);

n=read(fd, buffer, sizeof(buffer));

@@ -101,7 +165,8 @@ return (sgetc()); }

-afxipipestream::afxipipestream(int f) : std::istream(&fd_), fd_(f) +afxipipestream::afxipipestream(int f, time_t rto) + : std::istream(&fd_), fd_(f, rto, TIMEOUT_INF) { fd_.iosp=this; } @@ -110,7 +175,8 @@ { }

-afxopipestream::afxopipestream(int f) : std::ostream(&fd_), fd_(f) +afxopipestream::afxopipestream(int f, time_t wto) + : std::ostream(&fd_), fd_(f, TIMEOUT_INF, wto) { fd_.iosp=this; } @@ -120,7 +186,8 @@ }

-afxiopipestream::afxiopipestream(int f) : std::iostream(&fd_), fd_(f) +afxiopipestream::afxiopipestream(int f, time_t rto, time_t wto) + : std::iostream(&fd_), fd_(f, rto, wto) { fd_.iosp=this; } diff -ur afx/configure.in /home/jlam/milter/afx/configure.in --- afx/configure.in Mon Jul 30 00:25:54 2007 +++ /home/jlam/milter/afx/configure.in Tue Oct 23 20:49:44 2007 @@ -27,7 +27,7 @@

dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(unistd.h strings.h) +AC_CHECK_HEADERS(sys/time.h sys/select.h unistd.h strings.h)

dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff -ur afx/testafxpipe.C /home/jlam/milter/afx/testafxpipe.C --- afx/testafxpipe.C Sun Aug 5 20:00:33 2001 +++ /home/jlam/milter/afx/testafxpipe.C Tue Oct 23 20:54:15 2007 @@ -12,8 +12,8 @@ int fd0=dup(0); int fd1=dup(1);

- afxipipestream i(fd0); - afxopipestream o(fd1); + afxipipestream i(fd0, 10); + afxopipestream o(fd1, 10);

int c;