WvStreams
|
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 }