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
35{
37}
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.
Definition: uniclientconn.h:28
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
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
Definition: wvstream.h:25
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:1116
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:1089
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.
Definition: wvtclstring.cc:128