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 }