WvStreams
uniconfdaemonconn.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * Manages a UniConf daemon session.
6 */
7#include "uniconfdaemonconn.h"
8#include "uniconfdaemon.h"
9#include "wvtclstring.h"
10#include "wvstrutils.h"
11
12
13/***** UniConfDaemonConn *****/
14
15UniConfDaemonConn::UniConfDaemonConn(WvStream *_s, const UniConf &_root)
16 : UniClientConn(_s), root(_root)
17{
18 uses_continue_select = true;
19 addcallback();
20 writecmd(EVENT_HELLO,
21 spacecat(wvtcl_escape("UniConf Server ready."),
22 wvtcl_escape(UNICONF_PROTOCOL_VERSION)));
23}
24
25
26UniConfDaemonConn::~UniConfDaemonConn()
27{
28 close();
30 delcallback();
31}
32
33
38
39
40void UniConfDaemonConn::addcallback()
41{
42 root.add_callback(this, wv::bind(&UniConfDaemonConn::deltacallback, this,
43 _1, _2), true);
44}
45
46
47void UniConfDaemonConn::delcallback()
48{
49 root.del_callback(this, true);
50}
51
52
54{
56
57 WvString command_string;
58 UniClientConn::Command command = readcmd(command_string);
59
60 if (command != UniClientConn::NONE)
61 {
62 // parse and execute command
63 WvString arg1(readarg());
64 WvString arg2(readarg());
65 switch (command)
66 {
68 break;
69
71 do_invalid(command_string);
72 break;
73
75 do_noop();
76 break;
77
79 if (arg1.isnull())
80 do_malformed(command);
81 else
82 do_get(arg1);
83 break;
84
86 if (arg1.isnull() || arg2.isnull())
87 do_malformed(command);
88 else
89 do_set(arg1, arg2);
90 break;
91
93 if (arg1.isnull())
94 do_malformed(command);
95 else
96 do_remove(arg1);
97 break;
98
100 if (arg1.isnull())
101 do_malformed(command);
102 else
103 do_subtree(arg1, arg2.num() == 1);
104 break;
105
107 if (arg1.isnull())
108 do_malformed(command);
109 else
110 do_haschildren(arg1);
111 break;
112
114 do_commit();
115 break;
116
118 do_refresh();
119 break;
120
122 do_quit();
123 break;
124
126 do_help();
127 break;
128
129 default:
130 do_invalid(command_string);
131 break;
132 }
133 }
134}
135
136
137void UniConfDaemonConn::do_invalid(WvStringParm c)
138{
139 writefail(WvString("unknown command: %s", c));
140}
141
142
143void UniConfDaemonConn::do_malformed(UniClientConn::Command c)
144{
145 writefail(WvString("malformed request: %s",
146 UniClientConn::cmdinfos[c].name));
147}
148
149
150void UniConfDaemonConn::do_noop()
151{
152 writeok();
153}
154
155
156void UniConfDaemonConn::do_reply(WvStringParm reply)
157{
158 writefail("unexpected reply");
159}
160
161
162void UniConfDaemonConn::do_get(const UniConfKey &key)
163{
164 WvString value(root[key].getme());
165
166 if (value.isnull())
167 writefail();
168 else
169 writeonevalue(key, value);
170}
171
172
173void UniConfDaemonConn::do_set(const UniConfKey &key, WvStringParm value)
174{
175 root[key].setme(value);
176}
177
178
179void UniConfDaemonConn::do_remove(const UniConfKey &_key)
180{
181 int notifications_sent = 0;
182 bool single_key = true;
183
184 // Remove '/' at the end of the key
185 WvString strkey = _key;
186 for (int n = strkey.len()-1; n > 0; n--)
187 {
188 if (strkey.edit()[n] == '/')
189 strkey.edit()[n] = ' ';
190 else
191 break;
192 }
193
194 trim_string(strkey.edit());
195
196 UniConfKey key = strkey;
197
198 // Remove keys one at a time
199 UniConf cfg(root[key]);
200
201 if (cfg.exists())
202 {
204 for (it.rewind(); it.next(); )
205 {
206 single_key = false;
207 WvString sect_name = getdirname(it->fullkey());
208 root[it->fullkey()].remove();
209
210 if (sect_name == ".")
211 sect_name = WvString::null;
212
213 if (!root[sect_name].haschildren())
214 root[sect_name].remove();
215
216 // Don't hog the daemon while delivering notifications
217 if (++notifications_sent > CONTINUE_SELECT_AT)
218 {
219 notifications_sent = 0;
220
221 if (isok())
223 }
224 }
225
226 if (single_key)
227 root[key].remove();
228 }
229}
230
231
232void UniConfDaemonConn::do_subtree(const UniConfKey &key, bool recursive)
233{
234 static int niceness = 0;
235
236 UniConf cfg(root[key]);
237 if (cfg.exists())
238 {
239 if (recursive)
240 {
242 for (it.rewind(); it.next(); )
243 {
244 writevalue(it->fullkey(cfg), it._value());
245
246 // the output might be totally gigantic. Don't hog the
247 // entire daemon while fulfilling it; give up our timeslice
248 // after each entry.
249 if (!isok()) break;
250 if (++niceness > CONTINUE_SELECT_AT)
251 {
252 niceness = 0;
254 }
255 }
256 }
257 else
258 {
259 UniConf::Iter it(cfg);
260 for (it.rewind(); it.next(); )
261 {
262 writevalue(it->fullkey(cfg), it._value());
263
264 // the output might be totally gigantic. Don't hog the
265 // entire daemon while fulfilling it; give up our timeslice
266 // after each entry.
267 if (!isok()) break;
269 }
270 }
271 writeok();
272 }
273 else
274 writefail();
275}
276
277void UniConfDaemonConn::do_haschildren(const UniConfKey &key)
278{
279 bool haschild = root[key].haschildren();
281 spacecat(wvtcl_escape(key), haschild ? "TRUE" : "FALSE"));
282}
283
284
285void UniConfDaemonConn::do_commit()
286{
287 root.commit();
288 writeok();
289}
290
291
292void UniConfDaemonConn::do_refresh()
293{
294 if (root.refresh())
295 writeok();
296 else
297 writefail();
298}
299
300
301void UniConfDaemonConn::do_quit()
302{
303 writeok();
304 close();
305}
306
307
308void UniConfDaemonConn::do_help()
309{
310 for (int i = 0; i < UniClientConn::NUM_COMMANDS; ++i)
311 writetext(UniClientConn::cmdinfos[i].description);
312 writeok();
313}
314
315
316void UniConfDaemonConn::deltacallback(const UniConf &cfg, const UniConfKey &key)
317{
318 // for now, we just send notifications for *any* key that changes.
319 // Eventually we probably want to do something about having each
320 // connection specify exactly which keys it cares about.
321 WvString value(cfg[key].getme());
322 WvString msg;
323
324 UniConfKey fullkey(cfg.fullkey(cfg));
325 fullkey.append(key);
326
327 if (value.isnull())
328 msg = wvtcl_escape(fullkey);
329 else
330 msg = spacecat(wvtcl_escape(fullkey),
331 wvtcl_escape(cfg[key].getme()));
332
334}
Represents a connection to a UniConf daemon via any WvStream.
void writeonevalue(const UniConfKey &key, WvStringParm value)
Writes a PART_VALUE message.
virtual void close()
Close this stream.
Command readcmd()
Reads a command from the connection.
void writetext(WvStringParm text)
Writes a PART_TEXT message.
void writecmd(Command command, WvStringParm payload=WvString::null)
Writes a command to the connection.
void writefail(WvStringParm payload="")
Writes a REPLY_FAIL message.
WvString readarg()
Reads the next argument from the command payload.
void writeok(WvStringParm payload="")
Writes a REPLY_OK message.
void writevalue(const UniConfKey &key, WvStringParm value)
Writes a PART_VALUE message.
virtual void close()
Close this stream.
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition uniconfkey.h:39
This iterator walks through all immediate children of a UniConf node.
Definition uniconf.h:436
This iterator performs depth-first traversal of a subtree.
Definition uniconf.h:467
UniConf instances function as handles to subtrees of a UniConf tree and expose a high-level interface...
Definition uniconf.h:51
void commit() const
Commits information about this key recursively.
Definition uniconf.cc:125
void add_callback(void *cookie, const UniConfCallback &callback, bool recurse=true) const
Requests notification when any of the keys covered by the recursive depth specification change by inv...
Definition uniconf.cc:168
void remove() const
Removes this key and all of its children from the registry.
Definition uniconf.h:232
bool haschildren() const
Returns true if this key has children.
Definition uniconf.cc:56
void setme(WvStringParm value) const
Stores a string value for this key into the registry.
Definition uniconf.cc:83
bool refresh() const
Refreshes information about this key recursively.
Definition uniconf.cc:119
UniConfKey fullkey() const
Returns the full path of this node, starting at the root.
Definition uniconf.h:99
void del_callback(void *cookie, bool recurse=true) const
Cancels notification requested using add_callback().
Definition uniconf.cc:175
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition wvstring.h:94
int num() const
Return a stdc++ string with the contents of this string.
Definition wvstring.h:286
bool isnull() const
returns true if this string is null
Definition wvstring.h:290
virtual bool isok() const
return true if the stream is actually usable right now
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
Definition wvstream.h:25
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
Definition wvstream.h:652
void terminate_continue_select()
you MUST run this from your destructor if you use continue_select(), or very weird things will happen...
Definition wvstream.cc:1117
bool continue_select(time_t msec_timeout)
return to the caller from execute(), but don't really return exactly; this uses WvCont::yield() to re...
Definition wvstream.cc:1088
WvString is an implementation of a simple and efficient printable-string class.
Definition wvstring.h:330
char * edit()
make the string editable, and return a non-const (char*)
Definition wvstring.h:397
Various little string functions.
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
Definition strutils.cc:59
WvString spacecat(WvStringParm a, WvStringParm b, char sep=' ', bool onesep=false)
return the string formed by concatenating string 'a' and string 'b' with the 'sep' character between ...
Definition strutils.cc:114
Functions to handle "tcl-style" strings and lists.
WvString wvtcl_escape(WvStringParm s, const WvStringMask &nasties=WVTCL_NASTY_SPACES)
tcl-escape a string.