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 Sat Feb 21 21:05:27 2004 for WvStreams by doxygen 1.3.5