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 }
The basic interface which is included by all other XPLC interfaces and objects.
Definition: IObject.h:65
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...
virtual void nowrite()=0
Shuts down the writing side of the stream.
virtual bool isok() const =0
By default, returns true if geterr() == 0.
virtual void noread()=0
Shuts down the reading side of the stream.
virtual IWvStreamCallback setclosecallback(IWvStreamCallback _callfunc)=0
Sets a callback to be invoked on close().
virtual bool should_flush()=0
Returns true if we want to flush the output buffer right now.
Base class for different address types, each of which will have the ability to convert itself to/from...
Definition: wvaddr.h:119
size_t used() const
Returns the number of elements in the buffer currently available for reading.
Definition: wvbufbase.h:92
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
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
bool isnull() const
returns true if this string is null
Definition: wvstring.h:290
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:62
WvStreamClone simply forwards all requests to the "cloned" stream.
Definition: wvstreamclone.h:24
virtual void setclone(IWvStream *clone)
WvStreamClone takes ownership of the given stream; it will WVRELEASE() the stream when you setclone()...
virtual ~WvStreamClone()
The WvStreamClone destructor.
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
virtual void close()
Close this stream.
WvStreamClone(IWvStream *_cloned=NULL)
Constructs the stream, then calls setclone(_cloned).
virtual const WvAddr * src() const
get the remote address from which the last data block was received.
virtual bool isok() const
return true if the stream is actually usable right now
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
virtual void noread()
Shuts down the reading side of the stream.
virtual void nowrite()
Shuts down the writing side of the stream.
virtual size_t uread(void *buf, size_t size)
unbuffered I/O functions; these ignore the buffer, which is handled by read().
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
virtual int geterr() const
If isok() is false, return the system error number corresponding to the error, -1 for a special error...
virtual bool flush_internal(time_t msec_timeout)
WvStream overrides.
virtual size_t uwrite(const void *buf, size_t size)
unbuffered I/O functions; these ignore the buffer, which is handled by write().
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
Definition: wvstream.h:652
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
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
virtual bool isok() const
return true if the stream is actually usable right now
Definition: wvstream.cc:445
virtual void nowrite()
Shuts down the writing side of the stream.
Definition: wvstream.cc:576
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
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:1027
bool stop_read
True if noread()/nowrite()/close() have been called, respectively.
Definition: wvstream.h:57
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
Definition: wvstream.cc:844
bool select(time_t msec_timeout)
Return true if any of the requested features are true on the stream.
Definition: wvstream.h:376
virtual void close()
Close the stream if it is open; isok() becomes false from now on.
Definition: wvstream.cc:341
virtual void noread()
Shuts down the reading side of the stream.
Definition: wvstream.cc:569
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
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:330
the data structure used by pre_select()/post_select() and internally by select().
Definition: iwvstream.h:50
A SelectRequest is a convenient way to remember what we want to do to a particular stream: read from ...
Definition: iwvstream.h:34