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

Generated on Wed Dec 23 21:06:55 2009 for Vidalia by  doxygen 1.6.1