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

Generated on Sat Aug 16 17:38:35 2008 for Vidalia by  doxygen 1.5.6