torcontrol.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If 
00004 **  you did not receive the LICENSE file with this file, you may obtain it
00005 **  from the Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to
00008 **  the terms described in the LICENSE file.
00009 */
00010 
00011 /* 
00012 ** \file torcontrol.cpp
00013 ** \version $Id: torcontrol.cpp 2977 2008-08-17 01:28:25Z edmanm $
00014 ** \brief Object for interacting with the Tor process and control interface
00015 */
00016 
00017 #include <QHostAddress>
00018 #include <file.h>
00019 #include <stringutil.h>
00020 #include "torcontrol.h"
00021 
00022 
00023 /** Default constructor */
00024 TorControl::TorControl()
00025 {
00026   /* Create an instance of a connection to Tor's control interface and give
00027    * it an object to use to handle asynchronous events. */
00028   _controlConn = new ControlConnection(&_torEvents);
00029   QObject::connect(_controlConn, SIGNAL(connected()),
00030                    this, SLOT(onConnected()));
00031   QObject::connect(_controlConn, SIGNAL(connectFailed(QString)),
00032                    this, SLOT(onConnectFailed(QString)));
00033   QObject::connect(_controlConn, SIGNAL(disconnected()),
00034                    this, SLOT(onDisconnected()));
00035 
00036   /* Create an object used to start and stop a Tor process. */
00037   _torProcess = new TorProcess(this);
00038   QObject::connect(_torProcess, SIGNAL(started()),
00039                    this, SLOT(onStarted()));
00040   QObject::connect(_torProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
00041                    this, SLOT(onStopped(int, QProcess::ExitStatus)));
00042   QObject::connect(_torProcess, SIGNAL(startFailed(QString)),
00043                    this, SLOT(onStartFailed(QString)));
00044   QObject::connect(_torProcess, SIGNAL(log(QString, QString)),
00045                    this, SLOT(onLogStdout(QString, QString)));
00046 
00047 #if defined(Q_OS_WIN32)
00048   _torService = new TorService(this);
00049   QObject::connect(_torService, SIGNAL(started()), this, SLOT(onStarted()));
00050   QObject::connect(_torService, SIGNAL(finished(int, QProcess::ExitStatus)),
00051                    this, SLOT(onStopped(int, QProcess::ExitStatus)));
00052   QObject::connect(_torService, SIGNAL(startFailed(QString)),
00053                    this, SLOT(onStartFailed(QString))); 
00054 #endif
00055 }
00056 
00057 /** Default destructor */
00058 TorControl::~TorControl()
00059 {
00060   /* Disconnect the control socket */
00061   if (isConnected()) {
00062     disconnect();
00063   }
00064   /* If we started our own Tor, stop it now */
00065   if (isVidaliaRunningTor()) {
00066     stop();
00067   }
00068   delete _controlConn;
00069 }
00070 
00071 /** Start the Tor process using the executable <b>tor</b> and the list of
00072  * arguments in <b>args</b>. */
00073 void
00074 TorControl::start(const QString &tor, const QStringList &args)
00075 {
00076   if (isRunning()) {
00077     emit started();
00078   } else {
00079 #if defined(Q_OS_WIN32)
00080     /* If the Tor service is installed, run that. Otherwise, start a new
00081      * Tor process. */
00082     if (TorService::isSupported() && _torService->isInstalled())
00083       _torService->start();
00084     else
00085       _torProcess->start(expand_filename(tor), args);
00086 #else
00087     /* Start a new Tor process */
00088     _torProcess->start(expand_filename(tor), args);
00089 #endif
00090   }
00091 }
00092 
00093 /** Emits a signal that the Tor process started */
00094 void
00095 TorControl::onStarted()
00096 {
00097   emit started();
00098 }
00099 
00100 /** Emits a signal that the Tor process failed to start and includes an error
00101  * message (hopefully) indicating why. */
00102 void
00103 TorControl::onStartFailed(QString errmsg)
00104 {
00105   emit startFailed(errmsg);
00106 }
00107 
00108 /** Stop the Tor process. */
00109 bool
00110 TorControl::stop(QString *errmsg)
00111 {
00112   bool rc = false;
00113   if (_controlConn->isConnected())
00114     rc = signal(TorSignal::Halt, errmsg);
00115   if (!rc)
00116     rc = _torProcess->stop(errmsg);
00117   return rc;
00118 }
00119 
00120 /** Emits a signal that the Tor process stopped */
00121 void
00122 TorControl::onStopped(int exitCode, QProcess::ExitStatus exitStatus)
00123 {
00124   if (_controlConn->status() == ControlConnection::Connecting)
00125     _controlConn->cancelConnect();
00126   
00127   emit stopped();
00128   emit stopped(exitCode, exitStatus);
00129 }
00130 
00131 /** Detects if the Tor process is running under Vidalia. Returns true if
00132  * Vidalia owns the Tor process, or false if it was an independent Tor. */
00133 bool
00134 TorControl::isVidaliaRunningTor()
00135 {
00136   return (_torProcess->state() != QProcess::NotRunning);
00137 }
00138 
00139 /** Detect if the Tor process is running. */
00140 bool
00141 TorControl::isRunning()
00142 {
00143   return (_torProcess->state() != QProcess::NotRunning
00144             || _controlConn->isConnected());
00145 }
00146 
00147 /** Called when Tor has printed a log message to stdout. */
00148 void
00149 TorControl::onLogStdout(QString severity, QString message)
00150 {
00151   LogEvent::Severity s = LogEvent::toSeverity(severity);
00152   _torEvents.dispatch(TorEvents::toTorEvent(s), new LogEvent(s, message));
00153 }
00154 
00155 /** Connect to Tor's control port. The control port to use is determined by
00156  * Vidalia's configuration file. */
00157 void
00158 TorControl::connect(const QHostAddress &address, quint16 port)
00159 {
00160   _controlConn->connect(address, port);
00161 }
00162 
00163 /** Emits a signal that the control socket successfully established a
00164  * connection to Tor. */
00165 void
00166 TorControl::onConnected()
00167 {
00168   /* Let interested parties know that the control socket connected */
00169   emit connected();
00170 }
00171 
00172 /** Emits a signal that the control connection to Tor failed. */
00173 void
00174 TorControl::onConnectFailed(QString errmsg)
00175 {
00176   emit connectFailed(errmsg);
00177 }
00178 
00179 /** Disconnect from Tor's control port */
00180 void
00181 TorControl::disconnect()
00182 {
00183   if (isConnected())
00184     _controlConn->disconnect();
00185 }
00186 
00187 /** Emits a signal that the control socket disconnected from Tor */
00188 void
00189 TorControl::onDisconnected()
00190 {
00191   if (_torProcess) {
00192     /* If we're running a Tor process, then start reading logs from stdout
00193      * again, in case our control connection just died but Tor is still
00194      * running. In this case, there may be relevant information in the logs. */ 
00195     _torProcess->openStdout();
00196   }
00197   /* Tor isn't running, so it has no version */
00198   _torVersion = QString();
00199 
00200   /* Let interested parties know we lost our control connection */
00201   emit disconnected();
00202 }
00203 
00204 /** Check if the control socket is connected */
00205 bool
00206 TorControl::isConnected()
00207 {
00208   return _controlConn->isConnected();
00209 }
00210 
00211 /** Send a message to Tor and reads the response. If Vidalia was unable to
00212  * send the command to Tor or read its response, false is returned. If the
00213  * response was read and the status code is not 250 OK, false is also
00214  * returned. */
00215 bool
00216 TorControl::send(ControlCommand cmd, ControlReply &reply, QString *errmsg)
00217 {
00218   if (_controlConn->send(cmd, reply, errmsg)) {
00219     if (reply.getStatus() == "250") {
00220       return true;
00221     }
00222     if (errmsg) {
00223       *errmsg = reply.getMessage();
00224     }
00225   }
00226   return false;
00227 }
00228 
00229 /** Sends a message to Tor and discards the response. */
00230 bool
00231 TorControl::send(ControlCommand cmd, QString *errmsg)
00232 {
00233   ControlReply reply;
00234   return send(cmd, reply, errmsg);
00235 }
00236 
00237 /** Sends an authentication cookie to Tor. The syntax is:
00238  * 
00239  *   "AUTHENTICATE" SP 1*HEXDIG CRLF
00240  */
00241 bool
00242 TorControl::authenticate(const QByteArray cookie, QString *errmsg)
00243 {
00244   ControlCommand cmd("AUTHENTICATE", base16_encode(cookie));
00245   ControlReply reply;
00246   QString str;
00247   
00248   if (!send(cmd, reply, &str)) {
00249     emit authenticationFailed(str);
00250     return err(errmsg, str);
00251   }
00252   onAuthenticated(); 
00253   return true;
00254 }
00255 
00256 /** Sends an authentication password to Tor. The syntax is:
00257  * 
00258  *   "AUTHENTICATE" SP QuotedString CRLF
00259  */
00260 bool
00261 TorControl::authenticate(const QString password, QString *errmsg)
00262 {
00263   ControlCommand cmd("AUTHENTICATE", QString("%1")
00264                                       .arg(string_escape(password)));
00265   ControlReply reply;
00266   QString str;
00267   
00268   if (!send(cmd, reply, &str)) {
00269     emit authenticationFailed(str);
00270     return err(errmsg, str);
00271   }
00272   onAuthenticated(); 
00273   return true;
00274 }
00275 
00276 /** Called when the controller has successfully authenticated to Tor. */
00277 void
00278 TorControl::onAuthenticated()
00279 {
00280   /* The version of Tor isn't going to change while we're connected to it, so
00281    * save it for later. */
00282   getInfo("version", _torVersion);
00283   /* We want to use verbose names in events and GETINFO results. */
00284   useFeature("VERBOSE_NAMES");
00285 
00286   /* The control socket is connected, so we can stop reading from stdout */
00287   if (_torProcess)
00288     _torProcess->closeStdout();
00289   
00290   emit authenticated();
00291 }
00292 
00293 /** Sends a PROTOCOLINFO command to Tor and parses the response. */
00294 ProtocolInfo
00295 TorControl::protocolInfo(QString *errmsg)
00296 {
00297   ControlCommand cmd("PROTOCOLINFO", "1");
00298   ControlReply reply;
00299   ProtocolInfo pi;
00300   QString msg, topic;
00301   QHash<QString,QString> keyvals;
00302   int idx;
00303   bool ok;
00304 
00305   if (!send(cmd, reply, errmsg))
00306     return ProtocolInfo();
00307 
00308   foreach (ReplyLine line, reply.getLines()) {
00309     if (line.getStatus() != "250")
00310       continue;
00311     
00312     msg = line.getMessage().trimmed();
00313     idx = msg.indexOf(" ");
00314     topic = msg.mid(0, idx).toUpper();
00315     
00316     if (idx > 0) {
00317       keyvals = string_parse_keyvals(msg.mid(idx+1), &ok);
00318       if (!ok)
00319         continue; /* Ignore malformed lines */
00320     } else {
00321       keyvals = QHash<QString,QString>();
00322     }
00323    
00324     if (topic == "AUTH") {
00325       if (keyvals.contains("METHODS"))
00326         pi.setAuthMethods(keyvals.value("METHODS"));
00327       if (keyvals.contains("COOKIEFILE"))
00328         pi.setCookieAuthFile(keyvals.value("COOKIEFILE"));
00329     } else if (topic == "VERSION") {
00330       if (keyvals.contains("Tor"))
00331         pi.setTorVersion(keyvals.value("Tor"));
00332     }
00333   }
00334   return pi;
00335 }
00336 
00337 /** Tells Tor the controller wants to enable <b>feature</b> via the
00338  * USEFEATURE control command. Returns true if the given feature was
00339  * successfully enabled. */
00340 bool
00341 TorControl::useFeature(const QString &feature, QString *errmsg)
00342 {
00343   ControlCommand cmd("USEFEATURE", feature);
00344   return send(cmd, errmsg); 
00345 }
00346 
00347 BootstrapStatus
00348 TorControl::bootstrapStatus(QString *errmsg)
00349 {
00350   QString str = getInfo("status/bootstrap-phase").toString();
00351   if (!str.isEmpty()) {
00352     tc::Severity severity = tc::toSeverity(str.section(' ', 0, 0));
00353     QHash<QString,QString> args = string_parse_keyvals(str);
00354     return BootstrapStatus(severity,
00355               BootstrapStatus::statusFromString(args.value("TAG")),
00356               args.value("PROGRESS").toInt(),
00357               args.value("SUMMARY"),
00358               args.value("WARNING"),
00359               tc::toConnectionStatusReason(args.value("REASON")),
00360               BootstrapStatus::actionFromString(
00361                 args.value("RECOMMENDATION")));
00362   }
00363   return BootstrapStatus();
00364 }
00365 
00366 /** Returns true if Tor either has an open circuit or (on Tor >=
00367  * 0.2.0.1-alpha) has previously decided it's able to establish a circuit. */
00368 bool
00369 TorControl::circuitEstablished()
00370 {
00371   /* If Tor is recent enough, we can 'getinfo status/circuit-established' to
00372    * see if Tor has an open circuit */
00373   if (getTorVersion() >= 0x020001) {
00374     QString tmp;
00375     if (getInfo("status/circuit-established", tmp))
00376       return (tmp == "1");
00377   }
00378 
00379   /* Either Tor was too old or our getinfo failed, so try to get a list of all
00380    * circuits and check their statuses. */
00381   CircuitList circs = getCircuits();
00382   foreach (Circuit circ, circs) {
00383     if (circ.status() == Circuit::Built)
00384       return true;
00385   }
00386   return false;
00387 }
00388 
00389 /** Sends a GETINFO message to Tor based on the given map of keyvals. The
00390  * syntax is:
00391  * 
00392  *    "GETINFO" 1*(SP keyword) CRLF 
00393  */
00394 bool
00395 TorControl::getInfo(QHash<QString,QString> &map, QString *errmsg)
00396 {
00397   ControlCommand cmd("GETINFO");
00398   ControlReply reply;
00399 
00400   /* Add the keys as arguments to the GETINFO message */
00401   foreach (QString key, map.keys()) {
00402     cmd.addArgument(key);
00403   }
00404  
00405   /* Ask Tor for the specified info values */
00406   if (send(cmd, reply, errmsg)) {
00407     /* Parse the response for the returned values */
00408     foreach (ReplyLine line, reply.getLines()) {
00409       /* Split the "key=val" line and map them */
00410       QStringList keyval = line.getMessage().split("=");
00411       if (keyval.size() == 2) {
00412         map.insert(keyval.at(0), keyval.at(1));
00413       }
00414     }
00415     return true;
00416   }
00417   return false;
00418 }
00419 
00420 /** Sends a GETINFO message to Tor using the given list of <b>keys</b> and
00421  * returns a QVariantMap containing the specified keys and their values as
00422  * returned  by Tor. Returns a default constructed QVariantMap on failure. */
00423 QVariantMap
00424 TorControl::getInfo(const QStringList &keys, QString *errmsg)
00425 {
00426   ControlCommand cmd("GETINFO");
00427   ControlReply reply;
00428   QVariantMap infoMap;
00429 
00430   cmd.addArguments(keys);
00431   if (!send(cmd, reply, errmsg))
00432     return QVariantMap();
00433 
00434   foreach (ReplyLine line, reply.getLines()) {
00435     QString msg = line.getMessage();
00436     int index   = msg.indexOf("=");
00437     QString key = msg.mid(0, index);
00438     QStringList val;
00439    
00440     if (index > 0 && index < msg.length()-1)
00441       val << msg.mid(index+1);
00442     if (line.hasData())
00443       val << line.getData();
00444 
00445     if (infoMap.contains(key)) {
00446       QStringList values = infoMap.value(key).toStringList();
00447       values << val;
00448       infoMap.insert(key, values);
00449     } else {
00450       infoMap.insert(key, val);
00451     }
00452   }
00453   return infoMap;
00454 }
00455 
00456 /** Sends a GETINFO message to Tor with a single <b>key</b> and returns a
00457  * QVariant containing the value returned by Tor. Returns a default
00458  * constructed QVariant on failure. */
00459 QVariant
00460 TorControl::getInfo(const QString &key, QString *errmsg)
00461 {
00462   QVariantMap map = getInfo(QStringList() << key, errmsg);
00463   return map.value(key);
00464 }
00465 
00466 /** Overloaded method to send a GETINFO command for a single info value */
00467 bool
00468 TorControl::getInfo(QString key, QString &val, QString *errmsg)
00469 {
00470   QHash<QString,QString> map;
00471   map.insert(key, "");
00472 
00473   if (getInfo(map, errmsg)) {
00474     val = map.value(key);
00475     return true;
00476   }
00477   return false;
00478 }
00479 
00480 /** Sends a signal to Tor */
00481 bool
00482 TorControl::signal(TorSignal::Signal sig, QString *errmsg)
00483 {
00484   ControlCommand cmd("SIGNAL");
00485   cmd.addArgument(TorSignal::toString(sig));
00486 
00487   if (sig == TorSignal::Shutdown || sig == TorSignal::Halt) {
00488     /* Tor closes the connection before giving us a response to any commands
00489      * asking it to stop running, so don't try to get a response. */
00490     return _controlConn->send(cmd, errmsg);
00491   }
00492   return send(cmd, errmsg); 
00493 }
00494 
00495 /** Returns an address on which Tor is listening for application
00496  * requests. If none are available, a null QHostAddress is returned. */
00497 QHostAddress
00498 TorControl::getSocksAddress(QString *errmsg)
00499 {
00500   QHostAddress socksAddr;
00501 
00502   /* If SocksPort is 0, then Tor is not accepting any application requests. */
00503   if (getSocksPort() == 0) {
00504     return QHostAddress::Null;
00505   }
00506   
00507   /* Get a list of SocksListenAddress lines and return the first valid IP
00508    * address parsed from the list. */
00509   QStringList addrList = getSocksAddressList(errmsg);
00510   foreach (QString addr, addrList) {
00511     addr = addr.mid(0, addr.indexOf(":"));
00512     if (socksAddr.setAddress(addr)) {
00513       return socksAddr;
00514     }
00515   }
00516   /* Otherwise Tor is listening on its default 127.0.0.1 */
00517   return QHostAddress::LocalHost;
00518 }
00519 
00520 /** Returns a (possibly empty) list of all currently configured 
00521  * SocksListenAddress entries. */
00522 QStringList
00523 TorControl::getSocksAddressList(QString *errmsg)
00524 {
00525   QStringList addrList;
00526   if (getConf("SocksListenAddress", addrList, errmsg)) {
00527     return addrList;
00528   }
00529   return QStringList();
00530 }
00531 
00532 /** Returns a valid SOCKS port for Tor, or 0 if Tor is not accepting
00533  * application requests. */
00534 quint16
00535 TorControl::getSocksPort(QString *errmsg)
00536 {
00537   QList<quint16> portList = getSocksPortList(errmsg);
00538   if (portList.size() > 0) {
00539     return portList.at(0);
00540   }
00541   return 0;
00542 }
00543 
00544 /** Returns a list of all currently configured SOCKS ports. If Tor is not
00545  * accepting any application connections, an empty list will be returned. */
00546 QList<quint16>
00547 TorControl::getSocksPortList(QString *errmsg)
00548 {
00549   bool valid;
00550   quint16 port, socksPort;
00551   QString portString;
00552   QList<quint16> portList;
00553  
00554   /* Get the value of the SocksPort configuration variable */ 
00555   if (getConf("SocksPort", portString, errmsg)) {
00556     socksPort = (quint16)portString.toUInt(&valid);
00557     if (valid) {
00558       if (socksPort == 0) {
00559         /* A SocksPort of 0 means Tor is not accepting any application
00560          * connections. */
00561         return QList<quint16>();
00562       }
00563     }
00564   }
00565   /* Get a list of SOCKS ports from SocksListenAddress entries */
00566   QStringList addrList = getSocksAddressList(errmsg);
00567   foreach (QString addr, addrList) {
00568     if (addr.contains(":")) {
00569       portString = addr.mid(addr.indexOf(":")+1);
00570       port = (quint16)portString.toUInt(&valid);
00571       if (valid) {
00572         portList << port;
00573       }
00574     }
00575   }
00576   /* If there were no SocksListenAddress entries, or one or more of them did
00577    * not specify a port, then add the value of SocksPort, too */
00578   if (!portList.size() || (portList.size() != addrList.size())) {
00579     portList << socksPort;
00580   }
00581   return portList;
00582 }
00583 
00584 /** Reeturns Tor's version as a string. */
00585 QString
00586 TorControl::getTorVersionString()
00587 {
00588   return _torVersion;
00589 }
00590 
00591 /** Returns Tor's version as a numeric value. Note that this discards any
00592  * version status flag, such as "-alpha" or "-rc". */
00593 quint32
00594 TorControl::getTorVersion()
00595 {
00596   static QString versionString;
00597   static quint32 version = 0;
00598   quint8 major, minor, micro, patch;
00599 
00600   /* Only recompute the version number if the version string changed */
00601   if (versionString == _torVersion)
00602     return version;
00603   versionString = _torVersion;
00604 
00605   /* Split the version string at either "." or "-" characters */
00606   QStringList parts = versionString.split(QRegExp("\\.|-|\\ "));
00607   if (parts.size() >= 4) {
00608     major = (quint8)parts.at(0).toUInt();
00609     minor = (quint8)parts.at(1).toUInt();
00610     micro = (quint8)parts.at(2).toUInt();
00611     patch = (quint8)parts.at(3).toUInt();
00612     version = ((major << 24) | (minor << 16) | (micro << 8) | patch);
00613   } else {
00614     /* Couldn't parse the version string */
00615     version = 0;
00616   }
00617   return version;
00618 }
00619 
00620 /** Sets an event and its handler. If add is true, then the event is added,
00621  * otherwise it is removed. If set is true, then the given event will be
00622  * registered with Tor. */
00623 bool
00624 TorControl::setEvent(TorEvents::TorEvent e, QObject *obj, 
00625                      bool add, bool set, QString *errmsg)
00626 {
00627   if (add) {
00628     _torEvents.add(e, obj);
00629   } else {
00630     _torEvents.remove(e, obj);
00631   }
00632   if (set && isConnected()) {
00633     return setEvents(errmsg);
00634   }
00635   return true;
00636 }
00637 
00638 /** Registers for a set of logging events according to the given filter. If
00639  * the control socket is currently connected, this method will try to register
00640  * the log events with Tor, otherwise it will simply return true. */
00641 bool
00642 TorControl::setLogEvents(uint filter, QObject *obj, QString *errmsg)
00643 {
00644   setEvent(TorEvents::LogError , obj, filter & LogEvent::Error , false);
00645   setEvent(TorEvents::LogWarn  , obj, filter & LogEvent::Warn  , false);
00646   setEvent(TorEvents::LogNotice, obj, filter & LogEvent::Notice, false);
00647   setEvent(TorEvents::LogInfo  , obj, filter & LogEvent::Info  , false);
00648   setEvent(TorEvents::LogDebug , obj, filter & LogEvent::Debug , false);
00649   return (isConnected() ? setEvents(errmsg) : true);
00650 }
00651 
00652 /** Register for the events currently in the event list */
00653 bool
00654 TorControl::setEvents(QString *errmsg)
00655 {
00656   ControlCommand cmd("SETEVENTS"); 
00657   quint32 torVersion = getTorVersion();
00658 
00659   /* Add each event to the argument list */
00660   foreach (TorEvents::TorEvent e, _torEvents.eventList()) {
00661     if (torVersion < 0x010203
00662           && (e == TorEvents::GeneralStatus
00663                 || e == TorEvents::ClientStatus
00664                 || e == TorEvents::ServerStatus)) {
00665       /* Tor < 0.1.2.3-alpha does not support STATUS_GENERAL, STATUS_CLIENT
00666        * and STATUS_SERVER events. */
00667         continue;
00668     }
00669     cmd.addArgument(TorEvents::toString(e));
00670   }
00671   return send(cmd, errmsg);
00672 }
00673 
00674 /** Sets each configuration key in <b>map</b> to the value associated 
00675  * with its key. */
00676 bool
00677 TorControl::setConf(QHash<QString,QString> map, QString *errmsg)
00678 {
00679   ControlCommand cmd("SETCONF");
00680   
00681   /* Add each keyvalue to the argument list */
00682   foreach (QString key, map.uniqueKeys()) {
00683     foreach (QString value, map.values(key)) {
00684       if (value.length() > 0)
00685         cmd.addArgument(key + "=" + string_escape(value));
00686       else
00687         cmd.addArgument(key);
00688     }
00689   }
00690   return send(cmd, errmsg); 
00691 }
00692 
00693 /** Sets a single configuration key to the given value. */
00694 bool
00695 TorControl::setConf(QString key, QString value, QString *errmsg)
00696 {
00697   QHash<QString,QString> map;
00698   map.insert(key, value);
00699   return setConf(map, errmsg);
00700 }
00701 
00702 /** Sets a single configuration string that is formatted <key=escaped value>.*/
00703 bool
00704 TorControl::setConf(QString keyAndValue, QString *errmsg)
00705 {
00706   QHash<QString,QString> map;
00707   map.insert(keyAndValue, "");
00708   return setConf(map, errmsg);
00709 }
00710 
00711 /** Gets values for a set of configuration keys, each of which has a single
00712  * value. */
00713 bool
00714 TorControl::getConf(QHash<QString,QString> &map, QString *errmsg)
00715 {
00716   QHash<QString,QStringList> multiMap;
00717   foreach (QString key, map.keys()) {
00718     multiMap.insert(key, QStringList());
00719   }
00720   if (getConf(multiMap, errmsg)) {
00721     foreach (QString key, multiMap.keys()) {
00722       if (map.contains(key)) {
00723         map.insert(key, multiMap.value(key).join("\n"));
00724       }
00725     }
00726   }
00727   return false;
00728 }
00729 
00730 /** Gets a set of configuration keyvalues and stores them in <b>map</b>. */
00731 bool
00732 TorControl::getConf(QHash<QString,QStringList> &map, QString *errmsg)
00733 {
00734   ControlCommand cmd("GETCONF");
00735   ControlReply reply;
00736   QStringList confValue;
00737   QString confKey;
00738 
00739   /* Add the keys as arguments to the GETINFO message */
00740   foreach (QString key, map.keys()) {
00741     cmd.addArgument(key);
00742   }
00743 
00744   /* Ask Tor for the specified info values */
00745   if (send(cmd, reply, errmsg)) {
00746     /* Parse the response for the returned values */
00747     foreach (ReplyLine line, reply.getLines()) {
00748       /* Split the "key=val" line and map them */
00749       QStringList keyval = line.getMessage().split("=");
00750       if (keyval.size() == 2) {
00751         confKey = keyval.at(0);
00752        
00753         if (map.contains(confKey)) {
00754           /* This configuration key has multiple values, so add this one to
00755            * the list. */
00756           confValue = map.value(confKey);
00757         }
00758         confValue << keyval.at(1);
00759         map.insert(keyval.at(0), confValue);
00760       }
00761     }
00762     return true;
00763   }
00764   return false;
00765 }
00766 
00767 /** Gets a single configuration value for <b>key</b>. */
00768 bool
00769 TorControl::getConf(QString key, QString &value, QString *errmsg)
00770 {
00771   QStringList confValues;
00772   if (getConf(key, confValues, errmsg)) {
00773     value = confValues.join("\n");
00774     return true;
00775   }
00776   return false;
00777 }
00778 
00779 /** Gets a list of configuration values for <b>key</b>. */
00780 bool
00781 TorControl::getConf(QString key, QStringList &value, QString *errmsg)
00782 {
00783   QHash<QString,QStringList> map;
00784   map.insert(key, QStringList());
00785 
00786   if (getConf(map, errmsg)) {
00787     value = map.value(key);
00788     return true;
00789   }
00790   return false;
00791 }
00792 
00793 /** Sends a GETICONF message to Tor using the given list of <b>keys</b> and
00794  * returns a QVariantMap containing the specified keys and their values as
00795  * returned  by Tor. Returns a default constructed QVariantMap on failure. */
00796 QVariantMap
00797 TorControl::getConf(const QStringList &keys, QString *errmsg)
00798 {
00799   ControlCommand cmd("GETCONF");
00800   ControlReply reply;
00801   QVariantMap confMap;
00802 
00803   cmd.addArguments(keys);
00804   if (!send(cmd, reply, errmsg))
00805     return QVariantMap();
00806 
00807   foreach (ReplyLine line, reply.getLines()) {
00808     QString msg = line.getMessage();
00809     int index   = msg.indexOf("=");
00810     QString key = msg.mid(0, index);
00811     QString val;
00812    
00813     if (index > 0 && index < msg.length()-1)
00814       val = msg.mid(index+1);
00815 
00816     if (confMap.contains(key)) {
00817       QStringList values = confMap.value(key).toStringList();
00818       values << val;
00819       confMap.insert(key, values);
00820     } else {
00821       confMap.insert(key, val);
00822     }  
00823   }
00824   return confMap;
00825 }
00826 
00827 /** Sends a GETCONF message to Tor with a single <b>key</b> and returns a
00828  * QVariant containing the value returned by Tor. Returns a default
00829  * constructed QVariant on failure. */
00830 QVariant
00831 TorControl::getConf(const QString &key, QString *errmsg)
00832 {
00833   QVariantMap map = getConf(QStringList() << key, errmsg);
00834   return map.value(key);
00835 }
00836 
00837 /** Sends a GETCONF message to Tor with the single key and returns a QString
00838  * containing the value returned by Tor */
00839 QString
00840 TorControl::getHiddenServiceConf(const QString &key, QString *errmsg)
00841 {
00842   ControlCommand cmd("GETCONF");
00843   ControlReply reply;
00844   QVariantMap confMap;
00845 
00846   cmd.addArgument(key);
00847   if (!send(cmd, reply, errmsg))
00848     return "";
00849 
00850   return reply.toString();
00851 }
00852 
00853 /** Asks Tor to save the current configuration to its torrc. */
00854 bool
00855 TorControl::saveConf(QString *errmsg)
00856 {
00857   ControlCommand cmd("SAVECONF");
00858   return send(cmd, errmsg);
00859 }
00860 
00861 /** Tells Tor to reset the given configuration keys back to defaults. */
00862 bool
00863 TorControl::resetConf(QStringList keys, QString *errmsg)
00864 {
00865   ControlCommand cmd("RESETCONF");
00866 
00867   /* Add each key to the argument list */
00868   foreach (QString key, keys) {
00869     cmd.addArgument(key);
00870   }
00871   return send(cmd, errmsg);
00872 }
00873 
00874 /** Tells Tor to reset a single given configuration key back to its default
00875  * value. */
00876 bool
00877 TorControl::resetConf(QString key, QString *errmsg)
00878 {
00879   return resetConf(QStringList() << key, errmsg);
00880 }
00881 
00882 /** Returns the descriptor for the router whose fingerprint matches
00883  * <b>id</b>. If <b>id</b> is invalid or the router's descriptor cannot
00884  * be parsed, then an invalid RouterDescriptor is returned. */
00885 RouterDescriptor
00886 TorControl::getRouterDescriptor(const QString &id, QString *errmsg)
00887 {
00888   QStringList descriptor = getInfo("desc/id/" + id, errmsg).toStringList();
00889   return RouterDescriptor(descriptor);
00890 }
00891 
00892 /** Returns the status of the router whose fingerprint matches <b>id</b>. If
00893  * <b>id</b> is invalid or the router's status cannot be parsed, then an
00894  * invalid RouterStatus is returned. */
00895 RouterStatus
00896 TorControl::getRouterStatus(const QString &id, QString *errmsg)
00897 {
00898   QStringList status = getInfo("ns/id/" + id, errmsg).toStringList();
00899   return RouterStatus(status);
00900 }
00901 
00902 /** Returns a RouterStatus object for every known router in the network. If
00903  * the network status document cannot be parsed, then an empty NetworkStatus
00904  * is returned. */
00905 NetworkStatus
00906 TorControl::getNetworkStatus(QString *errmsg)
00907 {
00908   QStringList networkStatusLines = getInfo("ns/all", errmsg).toStringList();
00909   QList<RouterStatus> networkStatus;
00910   int len = networkStatusLines.size();
00911   int i = 0;
00912   
00913   while (i < len) {
00914     /* Extract the "r", "s", and whatever other status lines */
00915     QStringList routerStatusLines;
00916     do {
00917       routerStatusLines << networkStatusLines.at(i);
00918     } while (++i < len && ! networkStatusLines.at(i).startsWith("r "));
00919     
00920     /* Create a new RouterStatus object and add it to the network status, if
00921      * it's valid. */
00922     RouterStatus routerStatus(routerStatusLines);
00923     if (routerStatus.isValid())
00924       networkStatus << routerStatus;
00925   }
00926   return networkStatus;
00927 }
00928 
00929 /** Returns the annotations for the router whose fingerprint matches
00930  * <b>id</b>. If <b>id</b> is invalid or the router's annotations cannot be
00931  * parsed, then an empty DescriptorAnnotations is returned and <b>errmsg</b>
00932  * is set if it's not NULL. (Tor >= 0.2.0.13-alpha only) */
00933 DescriptorAnnotations
00934 TorControl::getDescriptorAnnotations(const QString &id, QString *errmsg)
00935 {
00936   QStringList lines = getInfo("desc-annotations/id/"+id, errmsg).toStringList();
00937   DescriptorAnnotations annotations;
00938   QString key, value;
00939 
00940   foreach (QString line, lines) {
00941     int idx = line.indexOf(" ");
00942     
00943     /* Extract the annotation key */
00944     key = line.mid(0, idx); 
00945     if (key.startsWith("@"))
00946       key = key.remove(0, 1);
00947     
00948     /* Extract the annotation value (if present) */
00949     if (idx > 0 && idx < line.length()-1)
00950       annotations.insert(key, line.mid(idx + 1).trimmed());
00951     else
00952       annotations.insert(key, QString());
00953   }
00954   return annotations;
00955 }
00956 
00957 /** Gets a list of current circuits. */
00958 QList<Circuit>
00959 TorControl::getCircuits(QString *errmsg)
00960 {
00961   ControlCommand cmd("GETINFO", "circuit-status");
00962   ControlReply reply;
00963   CircuitList circuits;
00964   
00965   if (!send(cmd, reply, errmsg))
00966     return CircuitList();
00967 
00968   /* The rest of the circuits just come as data, one per line */
00969   foreach(QString line, reply.getData()) {
00970     Circuit circ(line);
00971     if (circ.isValid())
00972       circuits << circ;
00973   }
00974   return circuits;
00975 }
00976 
00977 /** Closes the circuit specified by <b>circId</b>. If <b>ifUnused</b> is
00978  * true, then the circuit will not be closed unless it is unused. */
00979 bool
00980 TorControl::closeCircuit(const CircuitId &circId, bool ifUnused, QString *errmsg)
00981 {
00982   ControlCommand cmd("CLOSECIRCUIT", circId);
00983   if (ifUnused) {
00984     cmd.addArgument("IfUnused");
00985   }
00986   return send(cmd, errmsg);
00987 }
00988 
00989 /** Gets a list of current streams. */
00990 QList<Stream>
00991 TorControl::getStreams(QString *errmsg)
00992 {
00993   ControlCommand cmd("GETINFO", "stream-status");
00994   ControlReply reply;
00995   QList<Stream> streams;
00996   Stream s;
00997   
00998   if (send(cmd, reply, errmsg)) {
00999     /* Sometimes there is a stream on the first message line */
01000     QString msg = reply.getMessage();
01001     s = Stream::fromString(msg.mid(msg.indexOf("=")+1));
01002     if (s.isValid())
01003       streams << s;
01004     
01005     /* The rest of the streams just come as data, one per line */
01006     foreach (QString line, reply.getData()) {
01007       s = Stream::fromString(line);
01008       if (s.isValid())
01009         streams << s;
01010     }
01011   }
01012   return streams;
01013 }
01014 
01015 /** Closes the stream specified by <b>streamId</b>. */
01016 bool
01017 TorControl::closeStream(const StreamId &streamId, QString *errmsg)
01018 {
01019   ControlCommand cmd("CLOSESTREAM", streamId);
01020   cmd.addArgument("1"); /* 1 == REASON_MISC (tor-spec.txt) */
01021   return send(cmd, errmsg);
01022 }
01023 
01024  /** Gets a list of address mappings of the type specified by <b>type</b>
01025   * (defaults to <i>AddressMapAll</i>. */
01026 AddressMap
01027 TorControl::getAddressMap(AddressMap::AddressMapType type, QString *errmsg)
01028 {
01029   ControlCommand cmd("GETINFO");
01030   ControlReply reply;
01031   AddressMap addressMap;
01032 
01033   switch (type) {
01034     case AddressMap::AddressMapConfig:
01035       cmd.addArgument("addr-mappings/config");
01036       break;
01037     case AddressMap::AddressMapCache:
01038       cmd.addArgument("addr-mappings/cache");
01039       break;
01040     case AddressMap::AddressMapControl:
01041       cmd.addArgument("addr-mappings/control");
01042       break;
01043     default:
01044       cmd.addArgument("addr-mappings/all");
01045   }
01046 
01047   if (send(cmd, reply, errmsg)) {
01048     foreach (QString mapping, reply.getData()) {
01049       addressMap.add(mapping);
01050     }
01051   }
01052   return addressMap;
01053 }
01054 

Generated on Wed Nov 26 21:04:20 2008 for Vidalia by  doxygen 1.5.7.1