WvStreams
wvstreamclone.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvStreamClone simply forwards all requests to the "cloned" stream.
00006  * 
00007  * NOTE: this file is a pain to maintain, because many of these functions
00008  * are almost (but not quite) exactly like the ones in WvStream.  If
00009  * WvStream changes, you need to change this too.
00010  * 
00011  * See wvstreamclone.h.
00012  */
00013 #include "wvstreamclone.h"
00014 #include "wvmoniker.h"
00015 
00016 #ifdef _MSC_VER
00017 #pragma warning(disable : 4073)
00018 #pragma init_seg(lib)
00019 #endif
00020 
00021 static IWvStream *creator(WvStringParm s, IObject *_obj)
00022 {
00023     return new WvStreamClone(wvcreate<IWvStream>(s, _obj));
00024 }
00025 
00026 static IWvStream *objcreator(WvStringParm s, IObject *_obj)
00027 {
00028     // no real need to wrap it
00029 #if MUTATE_ISNT_BROKEN
00030     return mutate<IWvStream>(_obj);
00031 #else
00032     // HACK: we assume the object is safely of type IWvStream because
00033     // xplc's mutate<> function seems not to be working for some reason.
00034     return (IWvStream *)_obj;
00035 #endif
00036 }
00037 
00038 static WvMoniker<IWvStream> clonereg("clone", creator);
00039 static WvMoniker<IWvStream> objreg("obj", objcreator);
00040 static WvMoniker<IWvStream> objreg2("", objcreator);
00041 
00042 
00043 WvStreamClone::WvStreamClone(IWvStream *_cloned) 
00044     : cloned(NULL),
00045       my_type("WvStreamClone:(none)")
00046 {
00047     setclone(_cloned);
00048     // the sub-stream will force its own values, if it really wants.
00049     force_select(false, false, false);
00050 }
00051 
00052 
00053 WvStreamClone::~WvStreamClone()
00054 {
00055     //fprintf(stderr, "%p destroying: clone is %p\n", this, cloned);
00056     setclone(NULL);
00057     close();
00058 }
00059 
00060 
00061 void WvStreamClone::noread()
00062 {
00063     // unlike nowrite(), it is safe to call cloned->noread() immediately.
00064     // That will pass the shutdown(SHUT_RD) on to the deepest stream right
00065     // away, but won't close anything until all the inbufs are empty.
00066     if (cloned)
00067         cloned->noread();
00068     WvStream::noread();
00069 }
00070 
00071 
00072 void WvStreamClone::nowrite()
00073 {
00074     // this sets stop_write.  We call cloned->nowrite() in flush_internal()
00075     // when our outbuf is flushed (because until then, we *do* want to be
00076     // able to write to the clone).
00077     if (cloned && !outbuf.used())
00078         cloned->nowrite();
00079     WvStream::nowrite();
00080 }
00081 
00082 
00083 void WvStreamClone::close()
00084 {
00085     // fprintf(stderr, "%p closing substream %p\n", this, cloned);
00086     if (cloned)
00087         cloned->setclosecallback(0); // prevent recursion!
00088     WvStream::close();
00089     if (cloned)
00090         cloned->close();
00091 }
00092 
00093 
00094 bool WvStreamClone::flush_internal(time_t msec_timeout)
00095 {
00096     if (cloned)
00097     {
00098         if (stop_write && !outbuf.used())
00099             cloned->nowrite();
00100         return cloned->flush(msec_timeout);
00101     }
00102     else
00103         return true;
00104 }
00105 
00106 
00107 size_t WvStreamClone::uread(void *buf, size_t size)
00108 {
00109     // we use cloned->read() here, not uread(), since we want the _clone_
00110     // to own the input buffer, not the main stream.
00111     if (cloned)
00112     {
00113         size_t len = 0;
00114         if (cloned->isok())
00115             len = cloned->read(buf, size);
00116         if (len == 0 && !cloned->isok())
00117             close();
00118         return len;
00119     }
00120     else
00121         return 0;
00122 }
00123 
00124 
00125 size_t WvStreamClone::uwrite(const void *buf, size_t size)
00126 {
00127     // we use cloned->write() here, not uwrite(), since we want the _clone_
00128     // to own the output buffer, not the main stream.
00129     if (cloned)
00130         return cloned->write(buf, size);
00131     else
00132         return 0;
00133 }
00134 
00135 
00136 bool WvStreamClone::isok() const
00137 {
00138     if (geterr())
00139         return false;
00140     if (!cloned)
00141         return false;
00142     return WvStream::isok();
00143     
00144     // don't do this: cloned's closecallback will close us when needed.
00145     // return cloned->isok();
00146 }
00147 
00148 
00149 int WvStreamClone::geterr() const
00150 {
00151     if (WvStream::geterr())
00152         return WvStream::geterr();
00153     if (cloned)
00154         return cloned->geterr();
00155     return EIO;
00156 }
00157 
00158 
00159 WvString WvStreamClone::errstr() const
00160 {
00161     if (WvStream::geterr())
00162         return WvStream::errstr();
00163     if (cloned)
00164         return cloned->errstr();
00165     return "No child stream!";
00166 }
00167 
00168 
00169 void WvStreamClone::close_callback()
00170 {
00171     //fprintf(stderr, "streamclone-closecb: %d/%d/%d/%d/%d\n",
00172     //  stop_read, stop_write, outbuf.used(), inbuf.used(), closed);
00173     nowrite();
00174     noread();
00175     // close();
00176     //fprintf(stderr, "streamclone-closecb2: %d/%d/%d/%d/%d\n",
00177     //  stop_read, stop_write, outbuf.used(), inbuf.used(), closed);
00178 }
00179 
00180 
00181 void WvStreamClone::setclone(IWvStream *newclone)
00182 {
00183     if (cloned)
00184         cloned->setclosecallback(0);
00185     WVRELEASE(cloned);
00186     cloned = newclone;
00187     closed = stop_read = stop_write = false;
00188     if (cloned)
00189         cloned->setclosecallback(wv::bind(&WvStreamClone::close_callback,
00190                                           this));
00191     
00192     if (newclone != NULL)
00193         my_type = WvString("WvStreamClone:%s", newclone->wstype());
00194     else
00195         my_type = "WvStreamClone:(none)";
00196 }
00197 
00198 
00199 void WvStreamClone::pre_select(SelectInfo &si)
00200 {
00201     SelectRequest oldwant = si.wants;
00202     WvStream::pre_select(si);
00203 
00204     if (cloned && cloned->isok())
00205     {
00206         if (!si.inherit_request)
00207         {
00208             si.wants.readable |= static_cast<bool>(readcb);
00209             si.wants.writable |= static_cast<bool>(writecb);
00210             si.wants.isexception |= static_cast<bool>(exceptcb);
00211         }
00212         
00213         if (outbuf.used() || autoclose_time)
00214             si.wants.writable = true;
00215 
00216         cloned->pre_select(si);
00217         si.wants = oldwant;
00218     }
00219 }
00220 
00221 
00222 bool WvStreamClone::post_select(SelectInfo &si)
00223 {
00224     SelectRequest oldwant = si.wants;
00225     // This currently always returns false, but we prolly should
00226     // still have it here in case it ever becomes useful
00227     bool result = WvStream::post_select(si);
00228     bool val, want_write;
00229     
00230     if (cloned && cloned->should_flush())
00231         flush(0);
00232 
00233     if (cloned && cloned->isok())
00234     {
00235         if (!si.inherit_request)
00236         {
00237             si.wants.readable |= static_cast<bool>(readcb);
00238             si.wants.writable |= static_cast<bool>(writecb);
00239             si.wants.isexception |= static_cast<bool>(exceptcb);
00240         }
00241 
00242         val = cloned->post_select(si);
00243         want_write = si.wants.writable;
00244         si.wants = oldwant;
00245         
00246         // return result if they're looking for writable and we still
00247         // have data in outbuf - the writable is for flushing, not for you!
00248         if (want_write && outbuf.used())
00249             return result;
00250         else if (val && si.wants.readable && read_requires_writable
00251                  && !read_requires_writable->select(0, false, true))
00252             return result;
00253         else if (val && si.wants.writable && write_requires_readable
00254                  && !write_requires_readable->select(0, true, false))
00255             return result;
00256         else
00257             return val || result;
00258     }
00259     
00260     return result;
00261 }
00262 
00263 
00264 const WvAddr *WvStreamClone::src() const
00265 {
00266     if (cloned)
00267         return cloned->src();
00268     return NULL;
00269 }
00270 
00271 
00272 void WvStreamClone::execute()
00273 {
00274     WvStream::execute();
00275     if (cloned) cloned->callback();
00276 }
00277 
00278 WvString WvStreamClone::getattr(WvStringParm name) const
00279 {
00280     WvString ret = WvStream::getattr(name);
00281     if (ret.isnull() && cloned)
00282         return cloned->getattr(name);
00283 
00284     return ret;
00285 }