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
21static IWvStream *creator(WvStringParm s, IObject *_obj)
22{
23 return new WvStreamClone(wvcreate<IWvStream>(s, _obj));
24}
25
26static 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
38static WvMoniker<IWvStream> clonereg("clone", creator);
39static WvMoniker<IWvStream> objreg("obj", objcreator);
40static 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
94bool 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
107size_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
125size_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
159WvString 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
169void 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
278WvString 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.
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...
size_t used() const
Returns the number of elements in the buffer currently available for reading.
virtual int geterr() const
If isok() is false, return the system error number corresponding to the error, -1 for a special error...
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
bool isnull() const
returns true if this string is null
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
WvStreamClone simply forwards all requests to the "cloned" stream.
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...
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
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.
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.
WvStream * read_requires_writable
If this is set, select() doesn't return true for read unless the given stream also returns true for w...
virtual void close()
Close the stream if it is open; isok() becomes false from now on.
Definition wvstream.cc:341
WvStream * write_requires_readable
If this is set, select() doesn't return true for write unless the given stream also returns true for ...
virtual void noread()
Shuts down the reading side of the stream.
Definition wvstream.cc:569
WvString is an implementation of a simple and efficient printable-string class.
the data structure used by pre_select()/post_select() and internally by select().
A SelectRequest is a convenient way to remember what we want to do to a particular stream: read from ...