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 
15 UniConfDaemonConn::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 
26 UniConfDaemonConn::~UniConfDaemonConn()
27 {
28  close();
30  delcallback();
31 }
32 
33 
35 {
37 }
38 
39 
40 void UniConfDaemonConn::addcallback()
41 {
42  root.add_callback(this, wv::bind(&UniConfDaemonConn::deltacallback, this,
43  _1, _2), true);
44 }
45 
46 
47 void 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 
137 void UniConfDaemonConn::do_invalid(WvStringParm c)
138 {
139  writefail(WvString("unknown command: %s", c));
140 }
141 
142 
143 void UniConfDaemonConn::do_malformed(UniClientConn::Command c)
144 {
145  writefail(WvString("malformed request: %s",
146  UniClientConn::cmdinfos[c].name));
147 }
148 
149 
150 void UniConfDaemonConn::do_noop()
151 {
152  writeok();
153 }
154 
155 
156 void UniConfDaemonConn::do_reply(WvStringParm reply)
157 {
158  writefail("unexpected reply");
159 }
160 
161 
162 void 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 
173 void UniConfDaemonConn::do_set(const UniConfKey &key, WvStringParm value)
174 {
175  root[key].setme(value);
176 }
177 
178 
179 void 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  {
203  UniConf::RecursiveIter it(cfg);
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())
222  continue_select(0);
223  }
224  }
225 
226  if (single_key)
227  root[key].remove();
228  }
229 }
230 
231 
232 void 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  {
241  UniConf::RecursiveIter it(cfg);
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;
253  continue_select(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;
268  continue_select(0);
269  }
270  }
271  writeok();
272  }
273  else
274  writefail();
275 }
276 
277 void UniConfDaemonConn::do_haschildren(const UniConfKey &key)
278 {
279  bool haschild = root[key].haschildren();
281  spacecat(wvtcl_escape(key), haschild ? "TRUE" : "FALSE"));
282 }
283 
284 
285 void UniConfDaemonConn::do_commit()
286 {
287  root.commit();
288  writeok();
289 }
290 
291 
292 void UniConfDaemonConn::do_refresh()
293 {
294  if (root.refresh())
295  writeok();
296  else
297  writefail();
298 }
299 
300 
301 void UniConfDaemonConn::do_quit()
302 {
303  writeok();
304  close();
305 }
306 
307 
308 void 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 
316 void 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 }
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:93
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:38
This iterator performs depth-first traversal of a subtree.
Definition: uniconf.h:466
void remove() const
Removes this key and all of its children from the registry.
Definition: uniconf.h:232
Functions to handle "tcl-style" strings and lists.
Represents a connection to a UniConf daemon via any WvStream.
Definition: uniclientconn.h:27
This iterator walks through all immediate children of a UniConf node.
Definition: uniconf.h:435
void writevalue(const UniConfKey &key, WvStringParm value)
Writes a PART_VALUE message.
bool isnull() const
returns true if this string is null
Definition: wvstring.h:290
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
void commit() const
Commits information about this key recursively.
Definition: uniconf.cc:125
virtual bool isok() const
return true if the stream is actually usable right now
int num() const
Return a stdc++ string with the contents of this string.
Definition: wvstring.h:286
void writetext(WvStringParm text)
Writes a PART_TEXT message.
bool uses_continue_select
If this is set, enables the use of continue_select().
Definition: wvstream.h:45
void del_callback(void *cookie, bool recurse=true) const
Cancels notification requested using add_callback().
Definition: uniconf.cc:175
bool haschildren() const
Returns true if this key has children.
Definition: uniconf.cc:56
void append(const UniConfKey &other)
Appends a path to this path.
Definition: uniconfkey.cc:130
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...
WvString readarg()
Reads the next argument from the command payload.
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
Definition: wvstream.h:24
char * edit()
make the string editable, and return a non-const (char*)
Definition: wvstring.h:397
Command readcmd()
Reads a command from the connection.
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
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
UniConf instances function as handles to subtrees of a UniConf tree and expose a high-level interface...
Definition: uniconf.h:50
void writecmd(Command command, WvStringParm payload=WvString::null)
Writes a command to the connection.
WvString wvtcl_escape(WvStringParm s, const WvStringMask &nasties=WVTCL_NASTY_SPACES)
tcl-escape a string.
Definition: wvtclstring.cc:128
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
UniConfKey fullkey() const
Returns the full path of this node, starting at the root.
Definition: uniconf.h:99
Various little string functions.
void writeok(WvStringParm payload="")
Writes a REPLY_OK message.
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
Definition: strutils.cc:59
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
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
void writeonevalue(const UniConfKey &key, WvStringParm value)
Writes a PART_VALUE message.
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 writefail(WvStringParm payload="")
Writes a REPLY_FAIL message.
virtual void close()
Close this stream.