WvStreams
uniclientgen.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4  *
5  * UniClientGen is a UniConfGen for retrieving data from the
6  * UniConfDaemon.
7  */
8 #include "uniclientgen.h"
9 #include "unilistiter.h"
10 #include "wvaddr.h"
11 #include "wvfile.h"
12 #include "wvlinkerhack.h"
13 #include "wvmoniker.h"
14 #include "wvresolver.h"
15 #include "wvsslstream.h"
16 #include "wvstrutils.h"
17 #include "wvstringmask.h"
18 #include "wvtclstring.h"
19 #include "wvtcp.h"
20 
21 WV_LINK(UniClientGen);
22 
23 
24 #ifndef _WIN32
25 #include "wvunixsocket.h"
26 static IUniConfGen *unixcreator(WvStringParm s, IObject *)
27 {
28  WvConstInPlaceBuf buf(s, s.len());
29  WvString dst(wvtcl_getword(buf));
30  if (!dst) dst = "";
31 
32  return new UniClientGen(new WvUnixConn(dst), dst);
33 }
34 static WvMoniker<IUniConfGen> unixreg("unix", unixcreator);
35 #endif
36 
37 
38 static IUniConfGen *tcpcreator(WvStringParm _s, IObject *)
39 {
40  WvConstInPlaceBuf buf(_s, _s.len());
41  WvString dst(wvtcl_getword(buf));
42  if (!dst) dst = "";
43 
44  WvString s = dst;
45  char *cptr = s.edit();
46 
47  if (!strchr(cptr, ':')) // no default port
48  s.append(":%s", DEFAULT_UNICONF_DAEMON_TCP_PORT);
49 
50  return new UniClientGen(new WvTCPConn(s), dst);
51 }
52 
53 
54 static IUniConfGen *sslcreator(WvStringParm _s, IObject *)
55 {
56  WvConstInPlaceBuf buf(_s, _s.len());
57  WvString dst(wvtcl_getword(buf));
58  if (!dst) dst = "";
59 
60  WvString s = dst;
61  char *cptr = s.edit();
62 
63  if (!strchr(cptr, ':')) // no default port
64  s.append(":%s", DEFAULT_UNICONF_DAEMON_SSL_PORT);
65 
66  return new UniClientGen(new WvSSLStream(new WvTCPConn(s), NULL), dst);
67 }
68 
69 
70 static IUniConfGen *wvstreamcreator(WvStringParm s, IObject *_obj)
71 {
72  return new UniClientGen(wvcreate<IWvStream>(s, _obj));
73 }
74 
75 #ifdef WITH_SLP
76 #include "wvslp.h"
77 
78 // FIXME: Only gets the first
79 static IUniConfGen *slpcreator(WvStringParm s, IObject *)
80 {
81  WvStringList serverlist;
82 
83  if (slp_get_servs("uniconf.niti", serverlist))
84  {
85  WvString server = serverlist.popstr();
86  printf("Creating connection to: %s\n", server.cstr());
87  return new UniClientGen(new WvTCPConn(server), s);
88  }
89 
90  return NULL;
91 }
92 
93 static WvMoniker<IUniConfGen> slpreg("slp", slpcreator);
94 #endif
95 
96 static WvMoniker<IUniConfGen> tcpreg("tcp", tcpcreator);
97 static WvMoniker<IUniConfGen> sslreg("ssl", sslcreator);
98 static WvMoniker<IUniConfGen> wvstreamreg1("wvstream", wvstreamcreator);
99 static WvMoniker<IUniConfGen> wvstreamreg2("wv", wvstreamcreator);
100 
101 
102 
103 
104 /***** UniClientGen *****/
105 
107  : log(WvString("UniClientGen to %s",
108  dst.isnull() && stream->src()
109  ? *stream->src() : WvString(dst))),
110  timeout(60*1000),
111  version(0)
112 {
113  cmdinprogress = cmdsuccess = false;
114  result_list = NULL;
115 
116  conn = new UniClientConn(stream, dst);
117  conn->setcallback(wv::bind(&UniClientGen::conncallback, this));
118  WvIStreamList::globallist.append(conn, false, "uniclientconn-via-gen");
119 }
120 
121 
122 UniClientGen::~UniClientGen()
123 {
124  if (isok())
126  WvIStreamList::globallist.unlink(conn);
127  WVRELEASE(conn);
128 }
129 
130 
131 time_t UniClientGen::set_timeout(time_t _timeout)
132 {
133  if (_timeout < 1000)
134  timeout = 1000;
135  else
136  timeout = _timeout;
137  return timeout;
138 }
139 
140 
142 {
143  return (conn && conn->isok());
144 }
145 
146 
148 {
150  return do_select();
151 }
152 
154 {
155  // this ensures that all keys pending notifications are dealt with
156  while (conn->isok() && conn->isreadable())
157  conn->callback();
158 }
159 
161 {
163  do_select();
164 }
165 
167 {
168  WvString value;
170 
171  if (do_select())
172  {
173  if (result_key == key)
174  value = result;
175 // else
176 // seterror("Error: server sent wrong key pair.");
177  }
178  return value;
179 }
180 
181 
182 void UniClientGen::set(const UniConfKey &key, WvStringParm newvalue)
183 {
184  //set_queue.append(new WvString(key), true);
185  hold_delta();
186 
187  if (newvalue.isnull())
189  else
191  spacecat(wvtcl_escape(key),
192  wvtcl_escape(newvalue), ' '));
193 
194  flush_buffers();
195  unhold_delta();
196 }
197 
198 
199 void UniClientGen::setv(const UniConfPairList &pairs)
200 {
201  hold_delta();
202 
203  UniConfPairList::Iter i(pairs);
204  if (version >= 19)
205  {
206  // Much like how VAL works, SETV continues sending key-value pairs
207  // until it sends a terminating SETV, which has no arguments.
208  for (i.rewind(); i.next(); )
209  {
211  spacecat(wvtcl_escape(i->key()),
212  wvtcl_escape(i->value()), ' '));
213  }
215  }
216  else
217  {
218  for (i.rewind(); i.next(); )
219  {
220  set(i->key(), i->value());
221  }
222  }
223 
224  unhold_delta();
225 }
226 
227 
229 {
231 
232  if (do_select())
233  {
234  if (result_key == key && result == "TRUE")
235  return true;
236  }
237 
238  return false;
239 }
240 
241 
242 UniClientGen::Iter *UniClientGen::do_iterator(const UniConfKey &key,
243  bool recursive)
244 {
245  assert(!result_list);
246  result_list = new UniListIter(this);
248  WvString("%s %s", wvtcl_escape(key), WvString(recursive)));
249 
250  if (do_select())
251  {
252  ListIter *it = result_list;
253  result_list = NULL;
254  return it;
255  }
256  else
257  {
258  delete result_list;
259  result_list = NULL;
260  return NULL;
261  }
262 }
263 
264 
266 {
267  return do_iterator(key, false);
268 }
269 
270 
272 {
273  return do_iterator(key, true);
274 }
275 
276 
277 void UniClientGen::conncallback()
278 {
279  UniClientConn::Command command = conn->readcmd();
280  static const WvStringMask nasty_space(' ');
281  switch (command)
282  {
283  case UniClientConn::NONE:
284  // do nothing
285  break;
286 
288  cmdsuccess = true;
289  cmdinprogress = false;
290  break;
291 
293  result_key = WvString::null;
294  cmdsuccess = false;
295  cmdinprogress = false;
296  break;
297 
299  {
300  WvString key(wvtcl_getword(conn->payloadbuf, nasty_space));
301  WvString value(wvtcl_getword(conn->payloadbuf, nasty_space));
302 
303  if (!key.isnull() && !value.isnull())
304  {
305  result_key = key;
306  result = value;
307  cmdsuccess = true;
308  }
309  cmdinprogress = false;
310  break;
311 
312  }
313 
315  {
316  WvString key(wvtcl_getword(conn->payloadbuf, nasty_space));
317  WvString value(wvtcl_getword(conn->payloadbuf, nasty_space));
318 
319  if (!key.isnull() && !value.isnull())
320  {
321  result_key = key;
322  result = value;
323  cmdsuccess = true;
324  }
325 
326  cmdinprogress = false;
327  break;
328  }
329 
331  {
332  WvString key(wvtcl_getword(conn->payloadbuf, nasty_space));
333  WvString value(wvtcl_getword(conn->payloadbuf, nasty_space));
334 
335  if (!key.isnull() && !value.isnull())
336  {
337  if (result_list)
338  result_list->add(key, value);
339  }
340  break;
341  }
342 
344  {
345  WvStringList greeting;
346  wvtcl_decode(greeting, conn->payloadbuf.getstr(), nasty_space);
347  WvString server(greeting.popstr());
348  WvString version_string(greeting.popstr());
349 
350  if (server.isnull() || strncmp(server, "UniConf", 7))
351  {
352  // wrong type of server!
353  log(WvLog::Error, "Connected to a non-UniConf server!\n");
354 
355  cmdinprogress = false;
356  cmdsuccess = false;
357  conn->close();
358  }
359  else
360  {
361  version = 0;
362  sscanf(version_string, "%d", &version);
363  log(WvLog::Debug3, "UniConf version %s.\n", version);
364  }
365  break;
366  }
367 
369  {
370  WvString key(wvtcl_getword(conn->payloadbuf, nasty_space));
371  WvString value(wvtcl_getword(conn->payloadbuf, nasty_space));
372  delta(key, value);
373  }
374 
375  default:
376  // discard unrecognized commands
377  break;
378  }
379 }
380 
381 
382 // FIXME: horribly horribly evil!!
383 bool UniClientGen::do_select()
384 {
385  wvstime_sync();
386 
387  hold_delta();
388 
389  cmdinprogress = true;
390  cmdsuccess = false;
391 
392  time_t remaining = timeout;
393  const time_t clock_error = 10*1000;
394  WvTime timeout_at = msecadd(wvstime(), timeout);
395  while (conn->isok() && cmdinprogress)
396  {
397  // We would really like to run the "real" wvstreams globallist
398  // select loop here, but we can't because we may already be inside
399  // someone else's callback or something. So we'll wait on *only* this
400  // connection.
401  //
402  // We could do this using alarm()s, but because of very strage behaviour
403  // due to inherit_request in post_select when calling the long WvStream::select()
404  // prototype as we do here we have to do the remaining stuff outselves
405  time_t last_remaining = remaining;
406  bool result = conn->select(remaining, true, false);
407  remaining = msecdiff(timeout_at, wvstime());
408  if (result)
409  conn->callback();
410  else if (remaining <= 0 && remaining > -clock_error)
411  {
412  log(WvLog::Warning, "Command timeout; connection closed.\n");
413  cmdinprogress = false;
414  cmdsuccess = false;
415  conn->close();
416  }
417 
418  if (result
419  || remaining <= -clock_error
420  || remaining >= last_remaining + clock_error)
421  {
422  if (!result)
423  log(WvLog::Debug,
424  "Clock appears to have jumped; resetting"
425  " connection remaining.\n");
426  remaining = timeout;
427  timeout_at = msecadd(wvstime(), timeout);
428  }
429  }
430 
431 // if (!cmdsuccess)
432 // seterror("Error: server timed out on response.");
433 
434  unhold_delta();
435 
436  return cmdsuccess;
437 }
The basic interface which is included by all other XPLC interfaces and objects.
Definition: IObject.h:65
An abstract data container that backs a UniConf tree.
Definition: uniconfgen.h:40
::UniListIter ListIter
An iterator over a constant list of keys (see below)
Definition: uniconfgen.h:160
Represents a connection to a UniConf daemon via any WvStream.
Definition: uniclientconn.h:28
virtual void close()
Close this stream.
Command readcmd()
Reads a command from the connection.
void writecmd(Command command, WvStringParm payload=WvString::null)
Writes a command to the connection.
WvConstStringBuffer payloadbuf
Definition: uniclientconn.h:37
Communicates with a UniConfDaemon to fetch and store keys and values.
Definition: uniclientgen.h:29
virtual Iter * recursiveiterator(const UniConfKey &key)
Like iterator(), but the returned iterator is recursive, that is, it will return children of the imme...
virtual bool isok()
Determines if the generator is usable and working properly.
virtual void flush_buffers()
Flushes any commitment/notification buffers .
virtual void setv(const UniConfPairList &pairs)
Stores multiple key-value pairs into the registry.
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
virtual bool haschildren(const UniConfKey &key)
Returns true if a key has children.
UniClientGen(IWvStream *stream, WvStringParm dst=WvString::null)
Creates a generator which can communicate with a daemon using the specified stream.
virtual Iter * iterator(const UniConfKey &key)
Returns an iterator over the children of the specified key.
virtual WvString get(const UniConfKey &key)
Fetches a string value for a key from the registry.
virtual bool refresh()
Refreshes information about a key recursively.
virtual void commit()
Commits any changes.
An abstract iterator over keys and values in a generator.
Definition: uniconfgen.h:324
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
Definition: uniconfgen.cc:32
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
Definition: uniconfgen.cc:38
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key's value or children have possibly changed.
Definition: uniconfgen.cc:77
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:39
An iterator that iterates through a constant list of keys.
Definition: unilistiter.h:28
void add(const UniConfKey &k, WvStringParm v=WvString::null)
Add a key/value pair to the list that gets returned by this iterator.
Definition: unilistiter.cc:16
WvString getstr()
Returns the entire buffer as a null-terminated WvString.
Definition: wvbuffer.cc:17
The const in place raw memory buffer type.
Definition: wvbuf.h:188
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
const char * cstr() const
return a (const char *) for this string.
Definition: wvstring.h:267
bool isnull() const
returns true if this string is null
Definition: wvstring.h:290
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:62
SSL Stream, handles SSLv2, SSLv3, and TLS Methods - If you want it to be a server,...
Definition: wvsslstream.h:36
virtual bool isok() const
return true if the stream is actually usable right now
virtual bool isreadable()
Returns true if the stream is readable.
Definition: wvstream.cc:590
void setcallback(IWvStreamCallback _callfunc)
define the callback function for this stream, called whenever the callback() member is run,...
Definition: wvstream.cc:1129
bool select(time_t msec_timeout)
Return true if any of the requested features are true on the stream.
Definition: wvstream.h:376
virtual void callback()
if the stream has a callback function defined, call it now.
Definition: wvstream.cc:401
This is a WvList of WvStrings, and is a really handy way to parse strings.
Definition: wvstringlist.h:28
WvString popstr()
get the first string in the list, or an empty string if the list is empty.
Definition: wvstringlist.cc:55
A class used to provide a masked lookup for characters in a string.
Definition: wvstringmask.h:19
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
WvTCPConn tries to make all outgoing connections asynchronously (in the background).
Definition: wvtcp.h:40
Based on (and interchangeable with) struct timeval.
Definition: wvtimeutils.h:18
WvStream-based Unix domain socket connection class.
Definition: wvunixsocket.h:34
Various little string functions.
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
WvString wvtcl_getword(WvBuf &buf, const WvStringMask &splitchars=WVTCL_SPLITCHARS, bool do_unescape=true)
Get a single tcl word from an input buffer, and return the rest of the buffer untouched.
Definition: wvtclstring.cc:359
void wvtcl_decode(WvList< WvString > &l, WvStringParm _s, const WvStringMask &splitchars=WVTCL_SPLITCHARS, bool do_unescape=true)
split a tcl-style list.
Definition: wvtclstring.cc:386