Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvfdstream.cc

Go to the documentation of this file.
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Base class for streams built on Unix file descriptors. 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 // streams.cpp 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 // in win32, only sockets can be in the FD_SET for select() 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 /***** WvFDStream *****/ 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 //fprintf(stderr, "closing:%d/%d\n", rfd, wfd); 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; // interrupted 00093 00094 // a read that returns zero bytes signifies end-of-file (EOF). 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; // kernel buffer full - data not written 00113 00114 if (out < 0 || (count && out==0)) 00115 { 00116 seterr(out < 0 ? errno : 0); // a more critical error 00117 return 0; 00118 } 00119 00120 if (!outbuf.used() && want_nowrite && wfd < 0) 00121 { 00122 // copied from nowrite() 00123 if (rfd != wfd) 00124 ::close(wfd); 00125 else 00126 ::shutdown(rfd, SHUT_WR); // might be a socket 00127 00128 want_nowrite = false; 00129 wfd = -1; 00130 } 00131 00132 //TRACE("write obj 0x%08x, bytes %d/%d\n", (unsigned int)this, out, count); 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); // might be a socket 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); // might be a socket 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 // flush the output buffer if possible 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 // flush_outbuf() might have closed the file! 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 }

Generated on Tue Oct 5 01:09:20 2004 for WvStreams by doxygen 1.3.7