WvStreams
|
00001 /* 00002 * Worldvisions Tunnel Vision Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Manages a connection between the UniConf client and daemon. 00006 */ 00007 #include "uniclientconn.h" 00008 #include "wvaddr.h" 00009 #include "wvtclstring.h" 00010 #include "strutils.h" 00011 00012 /***** UniClientConn *****/ 00013 00014 /* This table is _very_ important!!! 00015 * 00016 * With UniConf, we promise to never remove or modify the behaviour of 00017 * any of the commands listed here. If you want to modify anything, 00018 * you'd better just add a new command instead. We keep track of the 00019 * version of the UniConf protocol by the number of commands supported 00020 * by the server. 00021 * 00022 * @see UniClientConn::Commands 00023 */ 00024 const UniClientConn::CommandInfo UniClientConn::cmdinfos[ 00025 UniClientConn::NUM_COMMANDS] = { 00026 // requests 00027 { "noop", "noop: verify that the connection is active" }, 00028 { "get", "get <key>: get the value of a key" }, 00029 { "set", "set <key> <value>: sets the value of a key" }, 00030 { "setv", "setv <key> <value> ...: set multiple key-value pairs" }, 00031 { "del", "del <key>: deletes the key" }, 00032 { "subt", "subt <key> <recurse?>: enumerates the children of a key" }, 00033 { "hchild", "hchild <key>: returns whether a key has children" }, 00034 { "commit", "commit: commits changes to disk" }, 00035 { "refresh", "refresh: refresh contents from disk" }, 00036 { "quit", "quit: kills the session nicely" }, 00037 { "help", "help: returns this help text" }, 00038 00039 // command completion replies 00040 { "OK", "OK <payload>: reply on command success" }, 00041 { "FAIL", "FAIL <payload>: reply on command failure" }, 00042 { "CHILD", "CHILD <key> TRUE / FALSE: key has children or not" }, 00043 { "ONEVAL", "ONEVAL <key> <value>: reply to a get" }, 00044 00045 // partial replies 00046 { "VAL", "VAL <key> <value>: intermediate reply value of a key" }, 00047 { "TEXT", "TEXT <text>: intermediate reply of a text message" }, 00048 00049 // events 00050 { "HELLO", "HELLO <version> <message>: sent by server on connection" }, 00051 { "NOTICE", "NOTICE <key> <oldval> <newval>: forget key and its children" }, 00052 }; 00053 00054 00055 UniClientConn::UniClientConn(IWvStream *_s, WvStringParm dst) : 00056 WvStreamClone(_s), 00057 log(WvString("UniConf to %s", dst.isnull() && _s->src() ? *_s->src() : WvString(dst)), 00058 WvLog::Debug5), closed(false), version(-1), payloadbuf("") 00059 { 00060 log("Opened\n"); 00061 } 00062 00063 00064 UniClientConn::~UniClientConn() 00065 { 00066 close(); 00067 } 00068 00069 00070 void UniClientConn::close() 00071 { 00072 if (!closed) 00073 { 00074 closed = true; 00075 WvStreamClone::close(); 00076 log("Closed\n"); 00077 } 00078 } 00079 00080 00081 WvString UniClientConn::readmsg() 00082 { 00083 WvString word; 00084 while ((word = wvtcl_getword(msgbuf, 00085 WVTCL_NASTY_NEWLINES, 00086 false)).isnull()) 00087 { 00088 // use lots of readahead to prevent unnecessary runs through select() 00089 // during heavy data transfers. 00090 char *line = getline(0, '\n', 20480); 00091 if (line) 00092 { 00093 msgbuf.putstr(line); 00094 msgbuf.put('\n'); 00095 } 00096 else 00097 { 00098 if (!WvStreamClone::isok()) 00099 { 00100 // possibly left some incomplete command behind 00101 msgbuf.zap(); 00102 } 00103 return WvString::null; 00104 } 00105 } 00106 if (!!word && 0) 00107 log("Read: %s\n", word); 00108 return word; 00109 } 00110 00111 00112 void UniClientConn::writemsg(WvStringParm msg) 00113 { 00114 write(msg); 00115 write("\n"); 00116 // log("Wrote: %s\n", msg); 00117 } 00118 00119 00120 UniClientConn::Command UniClientConn::readcmd() 00121 { 00122 WvString buf; 00123 return readcmd(buf); 00124 } 00125 00126 UniClientConn::Command UniClientConn::readcmd(WvString &command) 00127 { 00128 WvString msg(readmsg()); 00129 if (msg.isnull()) 00130 return NONE; 00131 00132 // extract command, leaving the remainder in payloadbuf 00133 payloadbuf.reset(msg); 00134 command = readarg(); 00135 00136 if (command.isnull()) 00137 return NONE; 00138 00139 for (int i = 0; i < NUM_COMMANDS; ++i) 00140 if (strcasecmp(cmdinfos[i].name, command.cstr()) == 0) 00141 return Command(i); 00142 return INVALID; 00143 } 00144 00145 00146 WvString UniClientConn::readarg() 00147 { 00148 return wvtcl_getword(payloadbuf); 00149 } 00150 00151 00152 void UniClientConn::writecmd(UniClientConn::Command cmd, WvStringParm msg) 00153 { 00154 if (msg) 00155 write(WvString("%s %s\n", cmdinfos[cmd].name, msg)); 00156 else 00157 write(WvString("%s\n", cmdinfos[cmd].name)); 00158 } 00159 00160 00161 void UniClientConn::writeok(WvStringParm payload) 00162 { 00163 writecmd(REPLY_OK, payload); 00164 } 00165 00166 00167 void UniClientConn::writefail(WvStringParm payload) 00168 { 00169 writecmd(REPLY_FAIL, payload); 00170 } 00171 00172 00173 void UniClientConn::writevalue(const UniConfKey &key, WvStringParm value) 00174 { 00175 if (value == WvString::null) 00176 writecmd(PART_VALUE, wvtcl_escape(key)); 00177 else 00178 writecmd(PART_VALUE, spacecat(wvtcl_escape(key), wvtcl_escape(value))); 00179 } 00180 00181 00182 void UniClientConn::writeonevalue(const UniConfKey &key, WvStringParm value) 00183 { 00184 writecmd(REPLY_ONEVAL, spacecat(wvtcl_escape(key), wvtcl_escape(value))); 00185 } 00186 00187 00188 void UniClientConn::writetext(WvStringParm text) 00189 { 00190 writecmd(PART_TEXT, wvtcl_escape(text)); 00191 } 00192 00193