Vidalia 0.2.15
ControlConnection.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.torproject.org/projects/vidalia.html. No part of Vidalia, 
00007 **  including this file, may be copied, modified, propagated, or distributed 
00008 **  except according to the terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file ControlConnection.cpp
00013 ** \brief A connection to Tor's control interface, responsible for sending and
00014 ** receiving commands and events
00015 */
00016 
00017 #include "ControlConnection.h"
00018 #include "tcglobal.h"
00019 #include "stringutil.h"
00020 
00021 #include <QCoreApplication>
00022 #include <QMutexLocker>
00023 
00024 /** Maximum number of times we'll try to connect to Tor before giving up.*/
00025 #define MAX_CONNECT_ATTEMPTS  5
00026 /** Time to wait between control connection attempts (in milliseconds). */
00027 #define CONNECT_RETRY_DELAY   2*1000
00028 
00029 
00030 /** Default constructor. */
00031 ControlConnection::ControlConnection(ControlMethod::Method method, TorEvents *events)
00032 {
00033   _events = events;
00034   _status = Unset;
00035   _sock = 0;
00036   _sendWaiter = new SendCommandEvent::SendWaiter();
00037   _method = method;
00038 }
00039 
00040 /** Destructor. */
00041 ControlConnection::~ControlConnection()
00042 {
00043   /* Exit the event loop */
00044   exit();
00045   /* Wait for the thread to finish */
00046   wait();
00047   /* Clean up after the send waiter */
00048   delete _sendWaiter;
00049 }
00050 
00051 /** Connect to the specified Tor control interface. */
00052 void
00053 ControlConnection::connect(const QHostAddress &addr, quint16 port)
00054 {
00055   if (isRunning()) {
00056     tc::error("Bug: Tried to call ControlConnection::connect() when the "
00057               "control thread is already running.");
00058     return;
00059   }
00060 
00061   /* Save the destination information */
00062   _addr = addr;
00063   _port = port;
00064   _sock = 0;
00065   _connectAttempt = 0;
00066   setStatus(Connecting);
00067 
00068   /* Kick off the thread in which the control socket will live */
00069   QThread::start();
00070 }
00071 
00072 /** Connect to the specified Tor control socket interface. */
00073 void
00074 ControlConnection::connect(const QString &addr)
00075 {
00076   if (isRunning()) {
00077     tc::error("Bug: Tried to call ControlConnection::connect() when the "
00078               "control thread is already running.");
00079     return;
00080   }
00081   
00082   _path = addr;
00083   _connectAttempt = 0;
00084   setStatus(Connecting);
00085 
00086   /* Kick off the thread in which the control socket will live */
00087   QThread::start();
00088 }
00089 
00090 /** Attempt to establish a connection to Tor's control interface. We will try
00091  * a maximum of MAX_CONNECT_ATTEMPTS, waiting CONNECT_RETRY_DELAY between each
00092  * attempt, to give slow Tors a chance to finish binding their control port. */
00093 void
00094 ControlConnection::connect()
00095 {
00096   _connectAttempt++;
00097   tc::debug("Connecting to Tor (Attempt %1 of %2)").arg(_connectAttempt)
00098                                                    .arg(MAX_CONNECT_ATTEMPTS);
00099   
00100   _connMutex.lock();
00101   switch(_method) {
00102     case ControlMethod::Socket:
00103       _sock->connectToServer(_path);
00104     break;
00105 
00106     default:
00107     case ControlMethod::Port:
00108       _sock->connectToHost(_addr, _port);
00109     break;
00110   }
00111   _connMutex.unlock();
00112 }
00113 
00114 /** Disconnect from Tor's control interface. */
00115 void
00116 ControlConnection::disconnect()
00117 {
00118   setStatus(Disconnecting);
00119   _connMutex.lock();
00120   switch(_method) {
00121     case ControlMethod::Socket:
00122       _sock->disconnectFromServer();
00123     break;
00124 
00125     default:
00126     case ControlMethod::Port:
00127       _sock->disconnectFromHost();
00128     break;
00129   }
00130   _connMutex.unlock();
00131 }
00132 
00133 /** Called when the control socket is connected. This method checks that the
00134  * control protocol version of the Tor we connected to is at least V1. */
00135 void
00136 ControlConnection::onConnected()
00137 {
00138   setStatus(Connected);
00139   emit connected();
00140 }
00141 
00142 /** Called when the control socket is disconnected and stops the control
00143  * thread's event loop. */
00144 void
00145 ControlConnection::onDisconnected()
00146 {
00147   setStatus(Disconnected);
00148   emit disconnected();
00149   exit(0);
00150 }
00151 
00152 /** Called when the control socket encounters <b>error</b>. */
00153 void
00154 ControlConnection::onError(QAbstractSocket::SocketError error)
00155 {
00156   if (status() == Connecting) {
00157     /* If we got a 'connection refused' and we haven't exceeded
00158      * MAX_CONNECT_ATTEMPTS, then try to reconnect since Tor is probably
00159      * running, but it doesn't have a ControlSocket open yet. */
00160     if (error == QAbstractSocket::ConnectionRefusedError &&
00161         _connectAttempt < MAX_CONNECT_ATTEMPTS) {
00162       tc::debug("Control connection refused. Retrying in %1ms.")
00163                                        .arg(CONNECT_RETRY_DELAY);
00164       _connectTimer->start(CONNECT_RETRY_DELAY);
00165     } else {
00166       /* Exceeded maximum number of connect attempts. Give up. */
00167       QString errstr = ControlSocket::toString(error);
00168       tc::error("Vidalia was unable to connect to Tor: %1").arg(errstr);
00169       emit connectFailed(tr("Vidalia was unable to connect to Tor. (%1)")
00170                                                              .arg(errstr));
00171       setStatus(Disconnected);
00172     }
00173   } else if (error == QAbstractSocket::RemoteHostClosedError) {
00174     /* Tor closed the connection. This is common when we send a 'shutdown' or
00175      * 'halt' signal to Tor and doesn't need to be logged as loudly. */
00176     tc::warn("Tor closed the control connection.");
00177   } else {
00178     /* Some other error. */
00179     /*XXX We may want to be emitting these so the GUI thread can learn about
00180      * them and display an error message. */
00181     tc::error("Control socket error: %1").arg(ControlSocket::toString(error));
00182   }
00183 }
00184 
00185 /** Cancels a pending control connection to Tor. */
00186 void
00187 ControlConnection::cancelConnect()
00188 {
00189   tc::warn("Control connection attempt cancelled.");
00190   setStatus(Disconnected);
00191   exit(0);
00192 }
00193 
00194 /** Returns true if the control socket is connected to Tor. */
00195 bool
00196 ControlConnection::isConnected()
00197 {
00198   return (status() == Connected);
00199 }
00200 
00201 /** Returns the status of the control connection. */
00202 ControlConnection::Status
00203 ControlConnection::status()
00204 {
00205   QMutexLocker locker(&_statusMutex);
00206   return _status;
00207 }
00208 
00209 /** Returns a string description of the control Status value
00210  * <b>status</b>. */
00211 QString
00212 ControlConnection::statusString(Status status)
00213 {
00214   QString str;
00215   switch (status) {
00216     case Unset:  str = "Unset"; break;
00217     case Disconnected:  str = "Disconnected"; break;
00218     case Disconnecting: str = "Disconnecting"; break;
00219     case Connecting: str = "Connecting"; break;
00220     case Connected: str = "Connected"; break;
00221     default:  str = "unknown";
00222   }
00223   return str;
00224 }
00225 
00226 /** Sets the control connection status. */
00227 void
00228 ControlConnection::setStatus(Status status)
00229 {
00230   QMutexLocker locker(&_statusMutex);
00231   tc::debug("Control connection status changed from '%1' to '%2'")
00232                                        .arg(statusString(_status))
00233                                        .arg(statusString(status));
00234   _status = status;
00235 }
00236 
00237 /** Sends a control command to Tor and waits for the reply. */
00238 bool
00239 ControlConnection::send(const ControlCommand &cmd,
00240                         ControlReply &reply, QString *errmsg)
00241 {
00242   bool result = false;
00243   QString errstr;
00244 
00245   _recvMutex.lock();
00246   if (send(cmd, &errstr)) {
00247     /* Create and enqueue a new receive waiter */
00248     ReceiveWaiter *w = new ReceiveWaiter();
00249     _recvQueue.enqueue(w);
00250     _recvMutex.unlock();
00251 
00252     /* Wait for and get the result, clean up, and return */
00253     result = w->getResult(&reply, &errstr);
00254     if (!result)
00255       tc::error("Failed to receive control reply: %1").arg(errstr);
00256     delete w;
00257   } else {
00258     tc::error("Failed to send control command (%1): %2").arg(cmd.keyword())
00259                                                         .arg(errstr);
00260     _recvMutex.unlock();
00261   }
00262 
00263   if (!result && errmsg)
00264     *errmsg = errstr;
00265   return result;
00266 }
00267 
00268 /** Sends a control command to Tor and returns true if the command was sent
00269  * successfully. Otherwise, returns false and <b>*errmsg</b> (if supplied)
00270  * will be set. */
00271 bool
00272 ControlConnection::send(const ControlCommand &cmd, QString *errmsg)
00273 {
00274   _connMutex.lock();
00275   if (!_sock || !_sock->isConnected()) {
00276     _connMutex.unlock();
00277     return err(errmsg, tr("Control socket is not connected.")); 
00278   }
00279   QCoreApplication::postEvent(_sock, new SendCommandEvent(cmd, _sendWaiter));
00280   _connMutex.unlock();
00281   
00282   return _sendWaiter->getResult(errmsg);
00283 }
00284 
00285 /** Called when there is data on the control socket. */
00286 void
00287 ControlConnection::onReadyRead()
00288 {
00289   QMutexLocker locker(&_connMutex);
00290   ReceiveWaiter *waiter;
00291   QString errmsg;
00292  
00293   while (_sock->canReadLine()) {
00294     ControlReply reply;
00295     if (_sock->readReply(reply, &errmsg)) {
00296       if (reply.getStatus() == "650") {
00297         /* Asynchronous event message */
00298         tc::debug("Control Event: %1").arg(reply.toString());
00299         
00300         if (_events) {
00301           _events->handleEvent(reply);
00302         }
00303       } else {
00304         /* Response to a previous command */
00305         tc::debug("Control Reply: %1").arg(reply.toString());
00306         
00307         _recvMutex.lock();
00308         if (!_recvQueue.isEmpty()) {
00309           waiter = _recvQueue.dequeue();
00310           waiter->setResult(true, reply);
00311         }
00312         _recvMutex.unlock();
00313       }
00314     } else {
00315       tc::error("Unable to read control reply: %1").arg(errmsg);
00316     }
00317   }
00318 }
00319 
00320 /** Main thread implementation. Creates and connects a control socket, then
00321  * spins up an event loop. */
00322 void
00323 ControlConnection::run()
00324 {
00325   /* Create a new control socket */
00326   _connMutex.lock();
00327   _sock = new ControlSocket(_method);
00328 
00329   _connectTimer = new QTimer();
00330   _connectTimer->setSingleShot(true);
00331   
00332   QObject::connect(_sock, SIGNAL(readyRead()), this, SLOT(onReadyRead()),
00333                    Qt::DirectConnection);
00334   QObject::connect(_sock, SIGNAL(disconnected()), this, SLOT(onDisconnected()),
00335                    Qt::DirectConnection);
00336   QObject::connect(_sock, SIGNAL(connected()), this, SLOT(onConnected()),
00337                    Qt::DirectConnection);
00338   QObject::connect(_sock, SIGNAL(error(QAbstractSocket::SocketError)), 
00339                    this, SLOT(onError(QAbstractSocket::SocketError)),
00340                    Qt::DirectConnection);
00341   QObject::connect(_connectTimer, SIGNAL(timeout()), this, SLOT(connect()),
00342                    Qt::DirectConnection);
00343 
00344   _connMutex.unlock();
00345   
00346   /* Attempt to connect to Tor */
00347   connect();
00348   tc::debug("Starting control connection event loop.");
00349   exec();
00350   tc::debug("Exited control connection event loop.");
00351 
00352   /* Clean up the socket */
00353   _connMutex.lock();
00354   _sock->disconnect(this);
00355   delete _sock;
00356   delete _connectTimer;
00357   _sock = 0;
00358   _connMutex.unlock();
00359 
00360   /* If there are any messages waiting for a response, clear them. */
00361   if (_sendWaiter->status() == SendCommandEvent::SendWaiter::Waiting)
00362     _sendWaiter->setResult(false, tr("Control socket is not connected."));
00363 
00364   _recvMutex.lock();
00365   while (!_recvQueue.isEmpty()) {
00366     ReceiveWaiter *w = _recvQueue.dequeue();
00367     w->setResult(false, ControlReply(), 
00368                  tr("Control socket is not connected."));
00369   }
00370   _recvMutex.unlock();
00371 }
00372 
00373 
00374 /*
00375  * ControlConnection::ReceiveWaiter
00376  */
00377 /** Waits for and gets the reply from a control command. */
00378 bool 
00379 ControlConnection::ReceiveWaiter::getResult(ControlReply *reply, 
00380                                             QString *errmsg)
00381 {
00382   forever {
00383     _mutex.lock();
00384     if (_status == Waiting) {
00385       _waitCond.wait(&_mutex);
00386       _mutex.unlock();
00387     } else {
00388       _mutex.unlock();
00389       break;
00390     }
00391   }
00392   if (errmsg) {
00393     *errmsg = _errmsg;
00394   }
00395   *reply = _reply;
00396   return (_status == Success);
00397 }
00398 
00399 /** Sets the result and reply from a control command. */
00400 void 
00401 ControlConnection::ReceiveWaiter::setResult(bool success, 
00402                                             const ControlReply &reply, 
00403                                             const QString &errmsg)
00404 {
00405   _mutex.lock();
00406   _status = (success ? Success : Failed);
00407   _reply = reply; 
00408   _errmsg = errmsg;
00409   _mutex.unlock();
00410   _waitCond.wakeAll();
00411 }
00412