7 #include "wvfdstream.h"
12 #include <sys/socket.h>
14 inline bool isselectable(
int fd)
21 #define getsockopt(a,b,c,d,e) getsockopt(a,b,c,(char *)d, e)
22 #define SHUT_RD SD_RECEIVE
23 #define SHUT_WR SD_SEND
24 #define ENOBUFS WSAENOBUFS
26 #define EAGAIN WSAEWOULDBLOCK
31 #define errno GetLastError()
34 static inline bool isselectable(
int s)
38 return ((HANDLE)_get_osfhandle(s) == INVALID_HANDLE_VALUE)
55 : rfd(_rwfd), wfd(_rwfd)
62 : rfd(_rfd), wfd(_wfd)
74 static int _cloexec(
int fd,
bool close_on_exec)
76 #ifndef _WIN32 // there is no exec() in win32, so this is meaningless there
77 return fcntl(fd, F_SETFD, close_on_exec ? FD_CLOEXEC : 0);
84 static int _nonblock(
int fd,
bool nonblock)
87 int flag = fcntl(fd, F_GETFL);
88 return fcntl(fd, F_SETFL,
89 (flag & ~O_NONBLOCK) | (nonblock ? O_NONBLOCK : 0));
91 u_long arg = nonblock ? 1 : 0;
92 return ioctlsocket(fd, FIONBIO, &arg);
101 _nonblock(
rfd, nonblock);
103 _nonblock(
wfd, nonblock);
111 _cloexec(
rfd, close_on_exec);
113 _cloexec(
wfd, close_on_exec);
142 assert(!count || buf);
143 if (!count || !buf || !
isok())
return 0;
150 if (in < 0 && (errno==EINTR || errno==EAGAIN || errno==ENOBUFS))
153 seterr(in < 0 ? errno : 0);
164 assert(!count || buf);
165 if (!buf || !count || !
isok())
return 0;
174 if (out < 0 && (err == ENOBUFS || err==EAGAIN))
177 seterr(out < 0 ? err : 0);
188 if (stop_write && !shutdown_write && !outbuf.
used())
190 shutdown_write =
true;
196 ::shutdown(
wfd, SHUT_WR);
206 ::shutdown(
rfd, SHUT_RD);
219 fprintf(stderr,
"%d/%d wr:%d ww:%d wx:%d inh:%d\n",
rfd,
wfd,
220 si.wants.readable, si.wants.writable, si.wants.isexception,
223 if (si.wants.readable && (
rfd >= 0))
225 if (isselectable(
rfd))
226 FD_SET(
rfd, &si.read);
233 if ((si.wants.writable || outbuf.
used() || autoclose_time) && (
wfd >= 0))
235 if (isselectable(
wfd))
236 FD_SET(
wfd, &si.write);
241 if (si.wants.isexception)
243 if (
rfd >= 0 && isselectable(
rfd)) FD_SET(
rfd, &si.except);
244 if (
wfd >= 0 && isselectable(
wfd)) FD_SET(
wfd, &si.except);
259 size_t outbuf_used = outbuf.
used();
260 if (
wfd >= 0 && (outbuf_used || autoclose_time)
270 bool rforce = si.wants.readable && !isselectable(
rfd),
271 wforce = si.wants.writable && !isselectable(
wfd);
273 (
rfd >= 0 && (rforce || FD_ISSET(
rfd, &si.read)))
274 || (
wfd >= 0 && (wforce || FD_ISSET(
wfd, &si.write)))
275 || (
rfd >= 0 && (FD_ISSET(
rfd, &si.except)))
276 || (
wfd >= 0 && (FD_ISSET(
wfd, &si.except)));
289 return val || result;
WvStream * write_requires_readable
If this is set, select() doesn't return true for write unless the given stream also returns true for ...
virtual void maybe_autoclose()
Auto-close the stream if the time is right.
virtual ~WvFdStream()
Destroys the stream and invokes close().
virtual size_t write(const void *buf, size_t count)
Write data to the stream.
virtual bool isok() const
return true if the stream is actually usable right now
WvStream * read_requires_writable
If this is set, select() doesn't return true for read unless the given stream also returns true for w...
virtual size_t uread(void *buf, size_t count)
unbuffered I/O functions; these ignore the buffer, which is handled by read().
bool select(time_t msec_timeout)
Return true if any of the requested features are true on the stream.
virtual size_t uwrite(const void *buf, size_t count)
unbuffered I/O functions; these ignore the buffer, which is handled by write().
int getrfd() const
Returns the Unix file descriptor for reading from this stream.
virtual void close()
Close the stream if it is open; isok() becomes false from now on.
virtual void seterr(int _errnum)
Override seterr() from WvError so that it auto-closes the stream.
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
the data structure used by pre_select()/post_select() and internally by select().
WvFdStream(int rwfd=-1)
Creates a WvStream from an existing file descriptor.
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
virtual void maybe_autoclose()
Auto-close the stream if the time is right.
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
virtual size_t read(void *buf, size_t count)
read a data block on the stream.
void set_close_on_exec(bool close_on_exec)
Make the fds on this stream close-on-exec or not.
virtual bool isok() const
return true if the stream is actually usable right now
virtual bool should_flush()
Returns true if we want to flush the output buffer right now.
virtual void close()
Closes the file descriptors.
int getwfd() const
Returns the Unix file descriptor for writing to this stream.
Base class for streams built on Unix file descriptors.
size_t used() const
Returns the number of elements in the buffer currently available for reading.
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
void set_nonblock(bool nonblock)
Make the fds on this stream blocking or non-blocking.
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
bool shutdown_read
Have we actually shut down the read/write sides?
int wfd
The file descriptor for writing.
int rfd
The file descriptor for reading.
bool stop_read
True if noread()/nowrite()/close() have been called, respectively.