00001
00002
00003
00004
00005
00006
00007
00008 #include "uniclientgen.h"
00009 #include "wvtclstring.h"
00010 #include "wvtcp.h"
00011 #include "wvaddr.h"
00012 #include "wvresolver.h"
00013 #include "wvmoniker.h"
00014 #include "wvsslstream.h"
00015
00016 #ifndef _WIN32
00017 #include "wvunixsocket.h"
00018 static UniConfGen *unixcreator(WvStringParm s, IObject *, void *)
00019 {
00020 return new UniClientGen(new WvUnixConn(s));
00021 }
00022 static WvMoniker<UniConfGen> unixreg("unix", unixcreator);
00023 #endif
00024
00025 static UniConfGen *tcpcreator(WvStringParm _s, IObject *, void *)
00026 {
00027 WvString s(_s);
00028 char *cptr = s.edit();
00029
00030 if (!strchr(cptr, ':'))
00031 s.append(":%s", DEFAULT_UNICONF_DAEMON_TCP_PORT);
00032
00033 return new UniClientGen(new WvTCPConn(s), _s);
00034 }
00035
00036 static UniConfGen *sslcreator(WvStringParm _s, IObject *, void *)
00037 {
00038 WvString s(_s);
00039 char *cptr = s.edit();
00040
00041 if (!strchr(cptr, ':'))
00042 s.append(":%s", DEFAULT_UNICONF_DAEMON_SSL_PORT);
00043
00044 return new UniClientGen(new WvSSLStream(new WvTCPConn(s), NULL, true), _s);
00045 }
00046
00047
00048
00049 static UniConfGen *wvstreamcreator(WvStringParm s, IObject *obj, void *)
00050 {
00051 IWvStream *stream = NULL;
00052 if (obj)
00053 stream = mutate<IWvStream>(obj);
00054 if (!stream)
00055 stream = wvcreate<IWvStream>(s);
00056 return new UniClientGen(stream);
00057 }
00058
00059 static WvMoniker<UniConfGen> tcpreg("tcp", tcpcreator);
00060 static WvMoniker<UniConfGen> sslreg("ssl", sslcreator);
00061 static WvMoniker<UniConfGen> wvstreamreg("wvstream", wvstreamcreator);
00062
00063
00064
00065
00066
00067 UniClientGen::UniClientGen(IWvStream *stream, WvStringParm dst) :
00068 conn(NULL), log(WvString("UniClientGen to %s",
00069 dst.isnull() ? *stream->src() : WvString(dst))),
00070 cmdinprogress(false), cmdsuccess(false)
00071 {
00072 conn = new UniClientConn(stream, dst);
00073 conn->setcallback(WvStreamCallback(this,
00074 &UniClientGen::conncallback), NULL);
00075
00076 deltastream.setcallback(WvStreamCallback(this, &UniClientGen::deltacb), 0);
00077 WvIStreamList::globallist.append(&deltastream, false);
00078 }
00079
00080
00081 UniClientGen::~UniClientGen()
00082 {
00083 WvIStreamList::globallist.unlink(&deltastream);
00084
00085 conn->writecmd(UniClientConn::REQ_QUIT, "");
00086 delete conn;
00087 }
00088
00089
00090 bool UniClientGen::isok()
00091 {
00092 return (conn && conn->isok());
00093 }
00094
00095
00096 bool UniClientGen::refresh()
00097 {
00098
00099 return true;
00100 }
00101
00102
00103 WvString UniClientGen::get(const UniConfKey &key)
00104 {
00105 WvString value;
00106 conn->writecmd(UniClientConn::REQ_GET, wvtcl_escape(key));
00107
00108 if (do_select())
00109 {
00110 if (result_key == key)
00111 value = result;
00112 else
00113 seterror("Error: server sent wrong key pair.");
00114 }
00115 return value;
00116 }
00117
00118
00119 void UniClientGen::set(const UniConfKey &key, WvStringParm newvalue)
00120 {
00121
00122 hold_delta();
00123
00124 if (newvalue.isnull())
00125 conn->writecmd(UniClientConn::REQ_REMOVE, wvtcl_escape(key));
00126 else
00127 conn->writecmd(UniClientConn::REQ_SET,
00128 WvString("%s %s", wvtcl_escape(key), wvtcl_escape(newvalue)));
00129
00130 unhold_delta();
00131 }
00132
00133
00134 bool UniClientGen::haschildren(const UniConfKey &key)
00135 {
00136 conn->writecmd(UniClientConn::REQ_HASCHILDREN, wvtcl_escape(key));
00137
00138 if (do_select())
00139 {
00140 if (result_key == key && result == "TRUE")
00141 return true;
00142 }
00143
00144 return false;
00145 }
00146
00147
00148 UniClientGen::Iter *UniClientGen::iterator(const UniConfKey &key)
00149 {
00150 result_list = new WvStringList();
00151 conn->writecmd(UniClientConn::REQ_SUBTREE, wvtcl_escape(key));
00152
00153 if (do_select())
00154 return new RemoteKeyIter(result_list);
00155
00156 delete result_list;
00157 return new UniConfGen::NullIter();
00158 }
00159
00160
00161 void UniClientGen::conncallback(WvStream &stream, void *userdata)
00162 {
00163 if (conn->alarm_was_ticking)
00164 {
00165
00166 log(WvLog::Error, "Command timeout; connection closed.\n");
00167 cmdinprogress = false;
00168 cmdsuccess = false;
00169 conn->close();
00170
00171 return;
00172 }
00173
00174 UniClientConn::Command command = conn->readcmd();
00175
00176 switch (command)
00177 {
00178 case UniClientConn::NONE:
00179
00180 break;
00181
00182 case UniClientConn::REPLY_OK:
00183 cmdsuccess = true;
00184 cmdinprogress = false;
00185 break;
00186
00187 case UniClientConn::REPLY_FAIL:
00188 result_key = WvString::null;
00189 cmdsuccess = false;
00190 cmdinprogress = false;
00191 break;
00192
00193 case UniClientConn::REPLY_CHILD:
00194 {
00195 WvString key(wvtcl_getword(conn->payloadbuf, " "));
00196 WvString value(wvtcl_getword(conn->payloadbuf, " "));
00197
00198 if (!key.isnull() && !value.isnull())
00199 {
00200 result_key = key;
00201 result = value;
00202 cmdsuccess = true;
00203 }
00204 cmdinprogress = false;
00205 break;
00206
00207 }
00208
00209 case UniClientConn::REPLY_ONEVAL:
00210 {
00211 WvString key(wvtcl_getword(conn->payloadbuf, " "));
00212 WvString value(wvtcl_getword(conn->payloadbuf, " "));
00213
00214 if (!key.isnull() && !value.isnull())
00215 {
00216 result_key = key;
00217 result = value;
00218 cmdsuccess = true;
00219 }
00220
00221 cmdinprogress = false;
00222 break;
00223 }
00224
00225 case UniClientConn::PART_VALUE:
00226 {
00227 WvString key(wvtcl_getword(conn->payloadbuf, " "));
00228 WvString value(wvtcl_getword(conn->payloadbuf, " "));
00229
00230 if (!key.isnull() && !value.isnull())
00231 {
00232 if (result_list)
00233 result_list->append(new WvString(key), true);
00234 }
00235 break;
00236 }
00237
00238 case UniClientConn::EVENT_HELLO:
00239 {
00240 WvString server(wvtcl_getword(conn->payloadbuf, " "));
00241
00242 if (server.isnull() || strncmp(server, "UniConf", 7))
00243 {
00244
00245 log(WvLog::Error, "Connected to a non-UniConf serer!\n");
00246
00247 cmdinprogress = false;
00248 cmdsuccess = false;
00249 conn->close();
00250 }
00251 break;
00252 }
00253
00254 case UniClientConn::EVENT_NOTICE:
00255 {
00256 WvString key(wvtcl_getword(conn->payloadbuf, " "));
00257 WvString value(wvtcl_getword(conn->payloadbuf, " "));
00258 clientdelta(key, value);
00259 }
00260
00261 default:
00262
00263 break;
00264 }
00265 }
00266
00267
00268 bool UniClientGen::do_select()
00269 {
00270 cmdinprogress = true;
00271 cmdsuccess = false;
00272
00273 conn->alarm(TIMEOUT);
00274 while (conn->isok() && cmdinprogress)
00275 {
00276 if (conn->select(-1))
00277 {
00278 conn->callback();
00279 conn->alarm(TIMEOUT);
00280 }
00281 }
00282 conn->alarm(-1);
00283
00284 if (!cmdsuccess)
00285 seterror("Error: server timed out on response.");
00286
00287 return cmdsuccess;
00288 }
00289
00290
00291
00292
00293
00294 void UniClientGen::RemoteKeyIter::rewind()
00295 {
00296 i.rewind();
00297 }
00298
00299
00300 bool UniClientGen::RemoteKeyIter::next()
00301 {
00302 return i.next();
00303 }
00304
00305
00306 UniConfKey UniClientGen::RemoteKeyIter::key() const
00307 {
00308 return UniConfKey(*i).last();
00309 }
00310
00311 void UniClientGen::clientdelta(const UniConfKey &key, WvStringParm value)
00312 {
00313 deltas.append(new UniConfPair(key, value), true);
00314 deltastream.alarm(0);
00315 }
00316
00317 void UniClientGen::deltacb(WvStream &, void *)
00318 {
00319 hold_delta();
00320 UniConfPairList::Iter i(deltas);
00321
00322 for (i.rewind(); i.next(); )
00323 delta(i->key(), i->value());
00324
00325 deltas.zap();
00326 unhold_delta();
00327 }