WvStreams
wvstreamclone.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4  *
5  * WvStreamClone simply forwards all requests to the "cloned" stream.
6  *
7  * NOTE: this file is a pain to maintain, because many of these functions
8  * are almost (but not quite) exactly like the ones in WvStream. If
9  * WvStream changes, you need to change this too.
10  *
11  * See wvstreamclone.h.
12  */
13 #include "wvstreamclone.h"
14 #include "wvmoniker.h"
15 
16 #ifdef _MSC_VER
17 #pragma warning(disable : 4073)
18 #pragma init_seg(lib)
19 #endif
20 
21 static IWvStream *creator(WvStringParm s, IObject *_obj)
22 {
23  return new WvStreamClone(wvcreate<IWvStream>(s, _obj));
24 }
25 
26 static IWvStream *objcreator(WvStringParm s, IObject *_obj)
27 {
28  // no real need to wrap it
29 #if MUTATE_ISNT_BROKEN
30  return mutate<IWvStream>(_obj);
31 #else
32  // HACK: we assume the object is safely of type IWvStream because
33  // xplc's mutate<> function seems not to be working for some reason.
34  return (IWvStream *)_obj;
35 #endif
36 }
37 
38 static WvMoniker<IWvStream> clonereg("clone", creator);
39 static WvMoniker<IWvStream> objreg("obj", objcreator);
40 static WvMoniker<IWvStream> objreg2("", objcreator);
41 
42 
44  : cloned(NULL),
45  my_type("WvStreamClone:(none)")
46 {
47  setclone(_cloned);
48  // the sub-stream will force its own values, if it really wants.
49  force_select(false, false, false);
50 }
51 
52 
54 {
55  //fprintf(stderr, "%p destroying: clone is %p\n", this, cloned);
56  setclone(NULL);
57  close();
58 }
59 
60 
62 {
63  // unlike nowrite(), it is safe to call cloned->noread() immediately.
64  // That will pass the shutdown(SHUT_RD) on to the deepest stream right
65  // away, but won't close anything until all the inbufs are empty.
66  if (cloned)
67  cloned->noread();
69 }
70 
71 
73 {
74  // this sets stop_write. We call cloned->nowrite() in flush_internal()
75  // when our outbuf is flushed (because until then, we *do* want to be
76  // able to write to the clone).
77  if (cloned && !outbuf.used())
78  cloned->nowrite();
80 }
81 
82 
84 {
85  // fprintf(stderr, "%p closing substream %p\n", this, cloned);
86  if (cloned)
87  cloned->setclosecallback(0); // prevent recursion!
89  if (cloned)
90  cloned->close();
91 }
92 
93 
94 bool WvStreamClone::flush_internal(time_t msec_timeout)
95 {
96  if (cloned)
97  {
98  if (stop_write && !outbuf.used())
99  cloned->nowrite();
100  return cloned->flush(msec_timeout);
101  }
102  else
103  return true;
104 }
105 
106 
107 size_t WvStreamClone::uread(void *buf, size_t size)
108 {
109  // we use cloned->read() here, not uread(), since we want the _clone_
110  // to own the input buffer, not the main stream.
111  if (cloned)
112  {
113  size_t len = 0;
114  if (cloned->isok())
115  len = cloned->read(buf, size);
116  if (len == 0 && !cloned->isok())
117  close();
118  return len;
119  }
120  else
121  return 0;
122 }
123 
124 
125 size_t WvStreamClone::uwrite(const void *buf, size_t size)
126 {
127  // we use cloned->write() here, not uwrite(), since we want the _clone_
128  // to own the output buffer, not the main stream.
129  if (cloned)
130  return cloned->write(buf, size);
131  else
132  return 0;
133 }
134 
135 
137 {
138  if (geterr())
139  return false;
140  if (!cloned)
141  return false;
142  return WvStream::isok();
143 
144  // don't do this: cloned's closecallback will close us when needed.
145  // return cloned->isok();
146 }
147 
148 
150 {
151  if (WvStream::geterr())
152  return WvStream::geterr();
153  if (cloned)
154  return cloned->geterr();
155  return EIO;
156 }
157 
158 
159 WvString WvStreamClone::errstr() const
160 {
161  if (WvStream::geterr())
162  return WvStream::errstr();
163  if (cloned)
164  return cloned->errstr();
165  return "No child stream!";
166 }
167 
168 
169 void WvStreamClone::close_callback()
170 {
171  //fprintf(stderr, "streamclone-closecb: %d/%d/%d/%d/%d\n",
172  // stop_read, stop_write, outbuf.used(), inbuf.used(), closed);
173  nowrite();
174  noread();
175  // close();
176  //fprintf(stderr, "streamclone-closecb2: %d/%d/%d/%d/%d\n",
177  // stop_read, stop_write, outbuf.used(), inbuf.used(), closed);
178 }
179 
180 
182 {
183  if (cloned)
184  cloned->setclosecallback(0);
185  WVRELEASE(cloned);
186  cloned = newclone;
187  closed = stop_read = stop_write = false;
188  if (cloned)
189  cloned->setclosecallback(wv::bind(&WvStreamClone::close_callback,
190  this));
191 
192  if (newclone != NULL)
193  my_type = WvString("WvStreamClone:%s", newclone->wstype());
194  else
195  my_type = "WvStreamClone:(none)";
196 }
197 
198 
200 {
201  SelectRequest oldwant = si.wants;
203 
204  if (cloned && cloned->isok())
205  {
206  if (!si.inherit_request)
207  {
208  si.wants.readable |= static_cast<bool>(readcb);
209  si.wants.writable |= static_cast<bool>(writecb);
210  si.wants.isexception |= static_cast<bool>(exceptcb);
211  }
212 
213  if (outbuf.used() || autoclose_time)
214  si.wants.writable = true;
215 
216  cloned->pre_select(si);
217  si.wants = oldwant;
218  }
219 }
220 
221 
223 {
224  SelectRequest oldwant = si.wants;
225  // This currently always returns false, but we prolly should
226  // still have it here in case it ever becomes useful
227  bool result = WvStream::post_select(si);
228  bool val, want_write;
229 
230  if (cloned && cloned->should_flush())
231  flush(0);
232 
233  if (cloned && cloned->isok())
234  {
235  if (!si.inherit_request)
236  {
237  si.wants.readable |= static_cast<bool>(readcb);
238  si.wants.writable |= static_cast<bool>(writecb);
239  si.wants.isexception |= static_cast<bool>(exceptcb);
240  }
241 
242  val = cloned->post_select(si);
243  want_write = si.wants.writable;
244  si.wants = oldwant;
245 
246  // return result if they're looking for writable and we still
247  // have data in outbuf - the writable is for flushing, not for you!
248  if (want_write && outbuf.used())
249  return result;
250  else if (val && si.wants.readable && read_requires_writable
251  && !read_requires_writable->select(0, false, true))
252  return result;
253  else if (val && si.wants.writable && write_requires_readable
254  && !write_requires_readable->select(0, true, false))
255  return result;
256  else
257  return val || result;
258  }
259 
260  return result;
261 }
262 
263 
265 {
266  if (cloned)
267  return cloned->src();
268  return NULL;
269 }
270 
271 
273 {
275  if (cloned) cloned->callback();
276 }
277 
278 WvString WvStreamClone::getattr(WvStringParm name) const
279 {
280  WvString ret = WvStream::getattr(name);
281  if (ret.isnull() && cloned)
282  return cloned->getattr(name);
283 
284  return ret;
285 }
WvStream::write_requires_readable
WvStream * write_requires_readable
If this is set, select() doesn't return true for write unless the given stream also returns true for ...
Definition: wvstream.h:42
WvErrorBase::geterr
virtual int geterr() const
If isok() is false, return the system error number corresponding to the error, -1 for a special error...
Definition: wverror.h:48
WvStreamClone::~WvStreamClone
virtual ~WvStreamClone()
The WvStreamClone destructor.
Definition: wvstreamclone.cc:53
WvStreamClone::execute
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
Definition: wvstreamclone.cc:272
WvStream::execute
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
Definition: wvstream.h:652
WvStream::read_requires_writable
WvStream * read_requires_writable
If this is set, select() doesn't return true for read unless the given stream also returns true for w...
Definition: wvstream.h:36
WvStreamClone::uread
virtual size_t uread(void *buf, size_t size)
unbuffered I/O functions; these ignore the buffer, which is handled by read().
Definition: wvstreamclone.cc:107
IWvStream::nowrite
virtual void nowrite()=0
Shuts down the writing side of the stream.
WvStream::flush
virtual bool flush(time_t msec_timeout)
flush the output buffer, if we can do it without delaying more than msec_timeout milliseconds at a ti...
Definition: wvstream.cc:707
WvStreamClone::close
virtual void close()
Close this stream.
Definition: wvstreamclone.cc:83
WvStream::select
bool select(time_t msec_timeout)
Return true if any of the requested features are true on the stream.
Definition: wvstream.h:376
IWvStream
Definition: iwvstream.h:24
WvStreamClone::uwrite
virtual size_t uwrite(const void *buf, size_t size)
unbuffered I/O functions; these ignore the buffer, which is handled by write().
Definition: wvstreamclone.cc:125
WvStream::close
virtual void close()
Close the stream if it is open; isok() becomes false from now on.
Definition: wvstream.cc:341
WvStreamClone::noread
virtual void noread()
Shuts down the reading side of the stream.
Definition: wvstreamclone.cc:61
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
WvFastString::isnull
bool isnull() const
returns true if this string is null
Definition: wvstring.h:290
WvStream::force_select
void force_select(bool readable, bool writable, bool isexception=false)
Use force_select() to force one or more particular modes (readable, writable, or isexception) to true...
Definition: wvstream.cc:1026
IWvStream::SelectInfo
the data structure used by pre_select()/post_select() and internally by select().
Definition: iwvstream.h:50
WvStreamClone::nowrite
virtual void nowrite()
Shuts down the writing side of the stream.
Definition: wvstreamclone.cc:72
WvMoniker
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:61
WvAddr
Base class for different address types, each of which will have the ability to convert itself to/from...
Definition: wvaddr.h:118
WvStream::post_select
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
Definition: wvstream.cc:875
WvStreamClone
WvStreamClone simply forwards all requests to the "cloned" stream.
Definition: wvstreamclone.h:23
IObject
Definition: IObject.h:65
WvStreamClone::setclone
virtual void setclone(IWvStream *clone)
WvStreamClone takes ownership of the given stream; it will WVRELEASE() the stream when you setclone()...
Definition: wvstreamclone.cc:181
IWvStream::isok
virtual bool isok() const =0
By default, returns true if geterr() == 0.
WvStream::isok
virtual bool isok() const
return true if the stream is actually usable right now
Definition: wvstream.cc:445
WvStreamClone::pre_select
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
Definition: wvstreamclone.cc:199
WvStreamClone::src
virtual const WvAddr * src() const
get the remote address from which the last data block was received.
Definition: wvstreamclone.cc:264
WvStreamClone::geterr
virtual int geterr() const
If isok() is false, return the system error number corresponding to the error, -1 for a special error...
Definition: wvstreamclone.cc:149
IWvStream::SelectRequest
A SelectRequest is a convenient way to remember what we want to do to a particular stream: read from ...
Definition: iwvstream.h:34
WvStreamClone::isok
virtual bool isok() const
return true if the stream is actually usable right now
Definition: wvstreamclone.cc:136
IWvStream::should_flush
virtual bool should_flush()=0
Returns true if we want to flush the output buffer right now.
IWvStream::setclosecallback
virtual IWvStreamCallback setclosecallback(IWvStreamCallback _callfunc)=0
Sets a callback to be invoked on close().
WvStream::nowrite
virtual void nowrite()
Shuts down the writing side of the stream.
Definition: wvstream.cc:576
WvBufBaseCommonImpl::used
size_t used() const
Returns the number of elements in the buffer currently available for reading.
Definition: wvbufbase.h:92
IWvStream::flush
virtual bool flush(time_t msec_timeout)=0
flush the output buffer, if we can do it without delaying more than msec_timeout milliseconds at a ti...
WvStreamClone::WvStreamClone
WvStreamClone(IWvStream *_cloned=NULL)
Constructs the stream, then calls setclone(_cloned).
Definition: wvstreamclone.cc:43
WvStream::pre_select
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
Definition: wvstream.cc:844
WvStreamClone::post_select
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
Definition: wvstreamclone.cc:222
IWvStream::noread
virtual void noread()=0
Shuts down the reading side of the stream.
WvStream::noread
virtual void noread()
Shuts down the reading side of the stream.
Definition: wvstream.cc:569
WvStream::stop_read
bool stop_read
True if noread()/nowrite()/close() have been called, respectively.
Definition: wvstream.h:57
WvStreamClone::flush_internal
virtual bool flush_internal(time_t msec_timeout)
WvStream overrides.
Definition: wvstreamclone.cc:94