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 }
WvString::edit
char * edit()
make the string editable, and return a non-const (char*)
Definition: wvstring.h:397
UniClientConn::EVENT_NOTICE
@ EVENT_NOTICE
Definition: uniclientconn.h:79
UniConf::refresh
bool refresh() const
Refreshes information about this key recursively.
Definition: uniconf.cc:119
UniClientConn::REQ_SUBTREE
@ REQ_SUBTREE
Definition: uniclientconn.h:60
UniConf::commit
void commit() const
Commits information about this key recursively.
Definition: uniconf.cc:125
UniClientConn::REQ_NOOP
@ REQ_NOOP
Definition: uniclientconn.h:55
UniClientConn::writeok
void writeok(WvStringParm payload="")
Writes a REPLY_OK message.
Definition: uniclientconn.cc:161
UniConf::del_callback
void del_callback(void *cookie, bool recurse=true) const
Cancels notification requested using add_callback().
Definition: uniconf.cc:175
UniClientConn::REQ_HASCHILDREN
@ REQ_HASCHILDREN
Definition: uniclientconn.h:61
UniClientConn::readarg
WvString readarg()
Reads the next argument from the command payload.
Definition: uniclientconn.cc:146
UniClientConn::INVALID
@ INVALID
Definition: uniclientconn.h:52
WvStreamClone::execute
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
Definition: wvstreamclone.cc:272
wvtclstring.h
UniConf::add_callback
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
UniConf::remove
void remove() const
Removes this key and all of its children from the registry.
Definition: uniconf.h:232
UniClientConn::REQ_HELP
@ REQ_HELP
Definition: uniclientconn.h:65
UniConf
UniConf instances function as handles to subtrees of a UniConf tree and expose a high-level interface...
Definition: uniconf.h:50
UniClientConn::writetext
void writetext(WvStringParm text)
Writes a PART_TEXT message.
Definition: uniclientconn.cc:188
trim_string
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
Definition: strutils.cc:59
spacecat
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
UniClientConn::REQ_GET
@ REQ_GET
Definition: uniclientconn.h:56
UniClientConn
Represents a connection to a UniConf daemon via any WvStream.
Definition: uniclientconn.h:27
UniClientConn::NONE
@ NONE
Definition: uniclientconn.h:51
WvStream::uses_continue_select
bool uses_continue_select
If this is set, enables the use of continue_select().
Definition: wvstream.h:45
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
WvFastString::isnull
bool isnull() const
returns true if this string is null
Definition: wvstring.h:290
wvtcl_escape
WvString wvtcl_escape(WvStringParm s, const WvStringMask &nasties=WVTCL_NASTY_SPACES)
tcl-escape a string.
Definition: wvtclstring.cc:128
UniClientConn::REQ_COMMIT
@ REQ_COMMIT
Definition: uniclientconn.h:62
wvstrutils.h
UniConfKey
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:38
WvStream::terminate_continue_select
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
UniClientConn::REQ_REMOVE
@ REQ_REMOVE
Definition: uniclientconn.h:59
UniConfDaemonConn::close
virtual void close()
Close this stream.
Definition: uniconfdaemonconn.cc:34
UniConf::setme
void setme(WvStringParm value) const
Stores a string value for this key into the registry.
Definition: uniconf.cc:83
WvStream
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
Definition: wvstream.h:24
UniClientConn::Command
Command
Definition: uniclientconn.h:49
UniClientConn::writefail
void writefail(WvStringParm payload="")
Writes a REPLY_FAIL message.
Definition: uniclientconn.cc:167
WvStreamClone::isok
virtual bool isok() const
return true if the stream is actually usable right now
Definition: wvstreamclone.cc:136
UniClientConn::writecmd
void writecmd(Command command, WvStringParm payload=WvString::null)
Writes a command to the connection.
Definition: uniclientconn.cc:152
UniConfDaemonConn::execute
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
Definition: uniconfdaemonconn.cc:53
UniClientConn::readcmd
Command readcmd()
Reads a command from the connection.
Definition: uniclientconn.cc:120
UniClientConn::writeonevalue
void writeonevalue(const UniConfKey &key, WvStringParm value)
Writes a PART_VALUE message.
Definition: uniclientconn.cc:182
UniConf::fullkey
UniConfKey fullkey() const
Returns the full path of this node, starting at the root.
Definition: uniconf.h:99
WvStream::continue_select
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
UniConf::haschildren
bool haschildren() const
Returns true if this key has children.
Definition: uniconf.cc:56
UniClientConn::REQ_QUIT
@ REQ_QUIT
Definition: uniclientconn.h:64
UniClientConn::close
virtual void close()
Close this stream.
Definition: uniclientconn.cc:70
UniConf::Iter
This iterator walks through all immediate children of a UniConf node.
Definition: uniconf.h:435
UniClientConn::REQ_SET
@ REQ_SET
Definition: uniclientconn.h:57
UniClientConn::REPLY_CHILD
@ REPLY_CHILD
Definition: uniclientconn.h:70
WvFastString::num
int num() const
Return a stdc++ string with the contents of this string.
Definition: wvstring.h:286
UniConf::RecursiveIter
This iterator performs depth-first traversal of a subtree.
Definition: uniconf.h:466
UniClientConn::REQ_REFRESH
@ REQ_REFRESH
Definition: uniclientconn.h:63
UniClientConn::writevalue
void writevalue(const UniConfKey &key, WvStringParm value)
Writes a PART_VALUE message.
Definition: uniclientconn.cc:173