00001
00002
00003
00004
00005
00006
00007
00008 #include "uniclientgen.h"
00009 #include "unilistiter.h"
00010 #include "wvaddr.h"
00011 #include "wvfile.h"
00012 #include "wvlinkerhack.h"
00013 #include "wvmoniker.h"
00014 #include "wvresolver.h"
00015 #include "wvsslstream.h"
00016 #include "wvstrutils.h"
00017 #include "wvstringmask.h"
00018 #include "wvtclstring.h"
00019 #include "wvtcp.h"
00020
00021 WV_LINK(UniClientGen);
00022
00023
00024 #ifndef _WIN32
00025 #include "wvunixsocket.h"
00026 static IUniConfGen *unixcreator(WvStringParm s)
00027 {
00028 return new UniClientGen(new WvUnixConn(s));
00029 }
00030 static WvMoniker<IUniConfGen> unixreg("unix", unixcreator);
00031 #endif
00032
00033
00034 static IUniConfGen *tcpcreator(WvStringParm _s)
00035 {
00036 WvString s(_s);
00037 char *cptr = s.edit();
00038
00039 if (!strchr(cptr, ':'))
00040 s.append(":%s", DEFAULT_UNICONF_DAEMON_TCP_PORT);
00041
00042 return new UniClientGen(new WvTCPConn(s), _s);
00043 }
00044
00045
00046 static IUniConfGen *sslcreator(WvStringParm _s)
00047 {
00048 WvString s(_s);
00049 char *cptr = s.edit();
00050
00051 if (!strchr(cptr, ':'))
00052 s.append(":%s", DEFAULT_UNICONF_DAEMON_SSL_PORT);
00053
00054 return new UniClientGen(new WvSSLStream(new WvTCPConn(s), NULL), _s);
00055 }
00056
00057
00058 static IUniConfGen *wvstreamcreator(WvStringParm s)
00059 {
00060 return new UniClientGen(wvcreate<IWvStream>(s));
00061 }
00062
00063 #ifdef WITH_SLP
00064 #include "wvslp.h"
00065
00066
00067 static IUniConfGen *slpcreator(WvStringParm s)
00068 {
00069 WvStringList serverlist;
00070
00071 if (slp_get_servs("uniconf.niti", serverlist))
00072 {
00073 WvString server = serverlist.popstr();
00074 printf("Creating connection to: %s\n", server.cstr());
00075 return new UniClientGen(new WvTCPConn(server), s);
00076 }
00077 else
00078 return NULL;
00079 }
00080
00081 static WvMoniker<IUniConfGen> slpreg("slp", slpcreator);
00082 #endif
00083
00084 static WvMoniker<IUniConfGen> tcpreg("tcp", tcpcreator);
00085 static WvMoniker<IUniConfGen> sslreg("ssl", sslcreator);
00086 static WvMoniker<IUniConfGen> wvstreamreg("wvstream", wvstreamcreator);
00087
00088
00089
00090
00091
00092
00093 UniClientGen::UniClientGen(IWvStream *stream, WvStringParm dst)
00094 : log(WvString("UniClientGen to %s",
00095 dst.isnull() && stream->src()
00096 ? *stream->src() : WvString(dst))),
00097 version(0)
00098 {
00099 cmdinprogress = cmdsuccess = false;
00100 result_list = NULL;
00101
00102 conn = new UniClientConn(stream, dst);
00103 conn->setcallback(WvStreamCallback(this,
00104 &UniClientGen::conncallback), NULL);
00105 WvIStreamList::globallist.append(conn, false, "uniclientconn-via-gen");
00106 }
00107
00108
00109 UniClientGen::~UniClientGen()
00110 {
00111 if (isok())
00112 conn->writecmd(UniClientConn::REQ_QUIT, "");
00113 WvIStreamList::globallist.unlink(conn);
00114 WVRELEASE(conn);
00115 }
00116
00117
00118 bool UniClientGen::isok()
00119 {
00120 return (conn && conn->isok());
00121 }
00122
00123
00124 bool UniClientGen::refresh()
00125 {
00126 conn->writecmd(UniClientConn::REQ_REFRESH);
00127 return do_select();
00128 }
00129
00130 void UniClientGen::flush_buffers()
00131 {
00132
00133 while (conn->isok() && conn->isreadable())
00134 conn->callback();
00135 }
00136
00137 void UniClientGen::commit()
00138 {
00139 conn->writecmd(UniClientConn::REQ_COMMIT);
00140 do_select();
00141 }
00142
00143 WvString UniClientGen::get(const UniConfKey &key)
00144 {
00145 WvString value;
00146 conn->writecmd(UniClientConn::REQ_GET, wvtcl_escape(key));
00147
00148 if (do_select())
00149 {
00150 if (result_key == key)
00151 value = result;
00152
00153
00154 }
00155 return value;
00156 }
00157
00158
00159 void UniClientGen::set(const UniConfKey &key, WvStringParm newvalue)
00160 {
00161
00162 hold_delta();
00163
00164 if (newvalue.isnull())
00165 conn->writecmd(UniClientConn::REQ_REMOVE, wvtcl_escape(key));
00166 else
00167 conn->writecmd(UniClientConn::REQ_SET,
00168 spacecat(wvtcl_escape(key),
00169 wvtcl_escape(newvalue), ' '));
00170
00171 flush_buffers();
00172 unhold_delta();
00173 }
00174
00175
00176 void UniClientGen::setv(const UniConfPairList &pairs)
00177 {
00178 hold_delta();
00179
00180 UniConfPairList::Iter i(pairs);
00181 if (version >= 19)
00182 {
00183
00184
00185 for (i.rewind(); i.next(); )
00186 {
00187 conn->writecmd(UniClientConn::REQ_SETV,
00188 spacecat(wvtcl_escape(i->key()),
00189 wvtcl_escape(i->value()), ' '));
00190 }
00191 conn->writecmd(UniClientConn::REQ_SETV);
00192 }
00193 else
00194 {
00195 for (i.rewind(); i.next(); )
00196 {
00197 set(i->key(), i->value());
00198 }
00199 }
00200
00201 unhold_delta();
00202 }
00203
00204
00205 bool UniClientGen::haschildren(const UniConfKey &key)
00206 {
00207 conn->writecmd(UniClientConn::REQ_HASCHILDREN, wvtcl_escape(key));
00208
00209 if (do_select())
00210 {
00211 if (result_key == key && result == "TRUE")
00212 return true;
00213 }
00214
00215 return false;
00216 }
00217
00218
00219 UniClientGen::Iter *UniClientGen::do_iterator(const UniConfKey &key,
00220 bool recursive)
00221 {
00222 assert(!result_list);
00223 result_list = new UniListIter(this);
00224 conn->writecmd(UniClientConn::REQ_SUBTREE,
00225 WvString("%s %s", wvtcl_escape(key), WvString(recursive)));
00226
00227 if (do_select())
00228 {
00229 ListIter *it = result_list;
00230 result_list = NULL;
00231 return it;
00232 }
00233 else
00234 {
00235 delete result_list;
00236 result_list = NULL;
00237 return NULL;
00238 }
00239 }
00240
00241
00242 UniClientGen::Iter *UniClientGen::iterator(const UniConfKey &key)
00243 {
00244 return do_iterator(key, false);
00245 }
00246
00247
00248 UniClientGen::Iter *UniClientGen::recursiveiterator(const UniConfKey &key)
00249 {
00250 return do_iterator(key, true);
00251 }
00252
00253
00254 time_t uptime()
00255 {
00256 WvFile f("/proc/uptime", O_RDONLY);
00257 if (f.isok())
00258 return WvString(f.getline(0)).num();
00259 return 0;
00260 }
00261
00262
00263 void UniClientGen::conncallback(WvStream &stream, void *userdata)
00264 {
00265 UniClientConn::Command command = conn->readcmd();
00266 static const WvStringMask nasty_space(' ');
00267 switch (command)
00268 {
00269 case UniClientConn::NONE:
00270
00271 break;
00272
00273 case UniClientConn::REPLY_OK:
00274 cmdsuccess = true;
00275 cmdinprogress = false;
00276 break;
00277
00278 case UniClientConn::REPLY_FAIL:
00279 result_key = WvString::null;
00280 cmdsuccess = false;
00281 cmdinprogress = false;
00282 break;
00283
00284 case UniClientConn::REPLY_CHILD:
00285 {
00286 WvString key(wvtcl_getword(conn->payloadbuf, nasty_space));
00287 WvString value(wvtcl_getword(conn->payloadbuf, nasty_space));
00288
00289 if (!key.isnull() && !value.isnull())
00290 {
00291 result_key = key;
00292 result = value;
00293 cmdsuccess = true;
00294 }
00295 cmdinprogress = false;
00296 break;
00297
00298 }
00299
00300 case UniClientConn::REPLY_ONEVAL:
00301 {
00302 WvString key(wvtcl_getword(conn->payloadbuf, nasty_space));
00303 WvString value(wvtcl_getword(conn->payloadbuf, nasty_space));
00304
00305 if (!key.isnull() && !value.isnull())
00306 {
00307 result_key = key;
00308 result = value;
00309 cmdsuccess = true;
00310 }
00311
00312 cmdinprogress = false;
00313 break;
00314 }
00315
00316 case UniClientConn::PART_VALUE:
00317 {
00318 WvString key(wvtcl_getword(conn->payloadbuf, nasty_space));
00319 WvString value(wvtcl_getword(conn->payloadbuf, nasty_space));
00320
00321 if (!key.isnull() && !value.isnull())
00322 {
00323 if (result_list)
00324 result_list->add(key, value);
00325 }
00326 break;
00327 }
00328
00329 case UniClientConn::EVENT_HELLO:
00330 {
00331 WvStringList greeting;
00332 wvtcl_decode(greeting, conn->payloadbuf.getstr(), nasty_space);
00333 WvString server(greeting.popstr());
00334 WvString version_string(greeting.popstr());
00335
00336 if (server.isnull() || strncmp(server, "UniConf", 7))
00337 {
00338
00339 log(WvLog::Error, "Connected to a non-UniConf serrer!\n");
00340
00341 cmdinprogress = false;
00342 cmdsuccess = false;
00343 conn->close();
00344 }
00345 else
00346 {
00347 version = 0;
00348 sscanf(version_string, "%d", &version);
00349 log(WvLog::Debug3, "UniConf version %s.\n", version);
00350 }
00351 break;
00352 }
00353
00354 case UniClientConn::EVENT_NOTICE:
00355 {
00356 WvString key(wvtcl_getword(conn->payloadbuf, nasty_space));
00357 WvString value(wvtcl_getword(conn->payloadbuf, nasty_space));
00358 delta(key, value);
00359 }
00360
00361 default:
00362
00363 break;
00364 }
00365 }
00366
00367
00368
00369 bool UniClientGen::do_select()
00370 {
00371 hold_delta();
00372
00373 cmdinprogress = true;
00374 cmdsuccess = false;
00375
00376 timeout_activity = uptime();
00377 while (conn->isok() && cmdinprogress)
00378 {
00379
00380
00381
00382
00383
00384
00385
00386
00387 if (conn->select(TIMEOUT, true, false))
00388 {
00389 conn->callback();
00390 timeout_activity = uptime();
00391 }
00392 else if (timeout_activity+3*(TIMEOUT/1000)/4 <= uptime())
00393 {
00394
00395 log(WvLog::Warning, "Command timeout; connection closed.\n");
00396 cmdinprogress = false;
00397 cmdsuccess = false;
00398 conn->close();
00399 }
00400 }
00401
00402
00403
00404
00405 unhold_delta();
00406
00407 return cmdsuccess;
00408 }