00001
00002
00003
00004
00005
00006
00007 #include "wvfdstream.h"
00008 #include "wvmoniker.h"
00009
00010 #ifndef _WIN32
00011 #include <sys/socket.h>
00012
00013 #define isselectable(fd) (true)
00014
00015 #else // _WIN32
00016
00017 #define getsockopt(a,b,c,d,e) getsockopt(a,b,c,(char *)d, e)
00018 #define SHUT_RD SD_RECEIVE
00019 #define SHUT_WR SD_SEND
00020 #define ENOBUFS WSAENOBUFS
00021 #define EAGAIN WSAEWOULDBLOCK
00022
00023
00024 int close(int fd);
00025 int read(int fd, void *buf, size_t count);
00026 int write(int fd, const void *buf, size_t count);
00027
00028 #undef errno
00029 #define errno GetLastError()
00030
00031
00032 inline bool isselectable(int s)
00033 {
00034 static u_long crap;
00035 return (ioctlsocket(s, FIONREAD, &crap) == 0) ? true : (GetLastError() != WSAENOTSOCK);
00036 }
00037
00038 #endif // _WIN32
00039
00040
00041
00042 static IWvStream *creator(WvStringParm s, IObject *, void *)
00043 {
00044 return new WvFDStream(s.num());
00045 }
00046
00047 static WvMoniker<IWvStream> reg("fd", creator);
00048
00049 WvFDStream::WvFDStream(int _rwfd)
00050 : rfd(_rwfd), wfd(_rwfd)
00051 {
00052 }
00053
00054
00055 WvFDStream::WvFDStream(int _rfd, int _wfd)
00056 : rfd(_rfd), wfd(_wfd)
00057 {
00058 }
00059
00060
00061 WvFDStream::~WvFDStream()
00062 {
00063 close();
00064 }
00065
00066
00067 void WvFDStream::close()
00068 {
00069 WvStream::close();
00070
00071 if (rfd >= 0)
00072 ::close(rfd);
00073 if (wfd >= 0 && wfd != rfd)
00074 ::close(wfd);
00075 rfd = wfd = -1;
00076 }
00077
00078
00079 bool WvFDStream::isok() const
00080 {
00081 return WvStream::isok() && (rfd != -1 || wfd != -1);
00082 }
00083
00084
00085 size_t WvFDStream::uread(void *buf, size_t count)
00086 {
00087 if (!isok() || !buf || !count) return 0;
00088
00089 int in = ::read(rfd, buf, count);
00090
00091 if (in < 0 && (errno==EINTR || errno==EAGAIN || errno==ENOBUFS))
00092 return 0;
00093
00094
00095 if (in < 0 || (count && in==0))
00096 {
00097 seterr(in < 0 ? errno : 0);
00098 return 0;
00099 }
00100
00101 return in;
00102 }
00103
00104
00105 size_t WvFDStream::uwrite(const void *buf, size_t count)
00106 {
00107 if (!isok() || !buf || !count) return 0;
00108
00109 int out = ::write(wfd, buf, count);
00110
00111 if (out < 0 && (errno == ENOBUFS || errno==EAGAIN))
00112 return 0;
00113
00114 if (out < 0 || (count && out==0))
00115 {
00116 seterr(out < 0 ? errno : 0);
00117 return 0;
00118 }
00119
00120 if (!outbuf.used() && want_nowrite && wfd < 0)
00121 {
00122
00123 if (rfd != wfd)
00124 ::close(wfd);
00125 else
00126 ::shutdown(rfd, SHUT_WR);
00127
00128 want_nowrite = false;
00129 wfd = -1;
00130 }
00131
00132
00133 return out;
00134 }
00135
00136
00137 void WvFDStream::noread()
00138 {
00139 if (rfd < 0)
00140 return;
00141 if (rfd != wfd)
00142 ::close(rfd);
00143 else
00144 ::shutdown(rfd, SHUT_RD);
00145 rfd = -1;
00146 }
00147
00148
00149 void WvFDStream::nowrite()
00150 {
00151 if (!outbuf.used())
00152 {
00153 if (rfd != wfd)
00154 ::close(wfd);
00155 else
00156 ::shutdown(rfd, SHUT_WR);
00157
00158 want_nowrite = false;
00159 wfd = -1;
00160 }
00161 else
00162 WvStream::nowrite();
00163 }
00164
00165
00166 bool WvFDStream::pre_select(SelectInfo &si)
00167 {
00168 bool result = WvStream::pre_select(si);
00169
00170 if (isselectable(rfd))
00171 {
00172 if (si.wants.readable && (rfd >= 0))
00173 FD_SET(rfd, &si.read);
00174 } else result |= si.wants.readable;
00175 if (isselectable(wfd))
00176 {
00177 if ((si.wants.writable || outbuf.used() || autoclose_time) && (wfd >= 0))
00178 FD_SET(wfd, &si.write);
00179 } else result |= si.wants.writable ;
00180
00181 if (si.wants.isexception)
00182 {
00183 if (rfd >= 0 && isselectable(rfd)) FD_SET(rfd, &si.except);
00184 if (wfd >= 0 && isselectable(wfd)) FD_SET(wfd, &si.except);
00185 }
00186 if (si.max_fd < rfd)
00187 si.max_fd = rfd;
00188 if (si.max_fd < wfd)
00189 si.max_fd = wfd;
00190 return result;
00191 }
00192
00193
00194 bool WvFDStream::post_select(SelectInfo &si)
00195 {
00196 bool result = WvStream::post_select(si);
00197
00198
00199 size_t outbuf_used = outbuf.used();
00200 if (wfd >= 0 && (outbuf_used || autoclose_time)
00201 && FD_ISSET(wfd, &si.write) && should_flush())
00202 {
00203 flush_outbuf(0);
00204
00205
00206 if (!isok()) return result;
00207 }
00208
00209 bool val = ((rfd >= 0 && FD_ISSET(rfd, &si.read)) ||
00210 (wfd >= 0 && FD_ISSET(wfd, &si.write)) ||
00211 (rfd >= 0 && FD_ISSET(rfd, &si.except)) ||
00212 (wfd >= 0 && FD_ISSET(wfd, &si.except)));
00213
00214 if (val && si.wants.readable && read_requires_writable
00215 && !read_requires_writable->select(0, false, true))
00216 return result;
00217 if (val && si.wants.writable && write_requires_readable
00218 && !write_requires_readable->select(0, true, false))
00219 return result;
00220 return val || result;
00221 }