torcontrol.cpp

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

Generated on Wed Sep 5 15:49:28 2007 for Vidalia by  doxygen 1.5.3