controlconnection.cpp

Go to the documentation of this file.
00001 /****************************************************************
00002  *  Vidalia is distributed under the following license:
00003  *
00004  *  Copyright (C) 2006,  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 controlconnection.cpp
00024  * \version $Id: controlconnection.cpp 1838 2007-08-21 04:33:02Z edmanm $
00025  * \brief A connection to Tor's control interface, responsible for sending and
00026  * receiving commands and events
00027  */
00028 
00029 #include <QMutexLocker>
00030 #include <util/string.h>
00031 #include <vidalia.h>
00032 
00033 #include "controlconnection.h"
00034 
00035 /** Maximum number of times we'll try to connect to Tor before giving up.*/
00036 #define MAX_CONNECT_ATTEMPTS  6
00037 /** Time to wait between control connection attempts (in microseconds). */
00038 #define CONNECT_RETRY_DELAY   500*1000
00039 
00040 
00041 /** Default constructor. */
00042 ControlConnection::ControlConnection(TorEvents *events)
00043 {
00044   _events = events;
00045   _sock = 0;
00046 }
00047 
00048 /** Destructor. */
00049 ControlConnection::~ControlConnection()
00050 {
00051   /* Exit the event loop */
00052   exit();
00053   /* Wait for the thread to finish. */
00054   wait();
00055 }
00056 
00057 /** Connect to the specified Tor control interface. */
00058 void
00059 ControlConnection::connect(QHostAddress addr, quint16 port)
00060 {
00061   /* Save the destination information */
00062   _addr = addr;
00063   _port = port;
00064   /* Kick off the thread in which the control socket will live */
00065   QThread::start();
00066 }
00067 
00068 /** Attempt to establish a connection to Tor's control interface. We will try
00069 * a maximum of MAX_CONNECT_ATTEMPTS, waiting CONNECT_RETRY_DELAY between each
00070 * attempt, to give slow Tors a chance to finish binding their control port. */
00071 bool
00072 ControlConnection::connect()
00073 {
00074   QString errmsg;
00075   bool result;
00076   
00077   setStatus(Connecting);
00078   for (int i = 0; i < MAX_CONNECT_ATTEMPTS; i++) {
00079     /* Check if we're supposed to cancel our attempt to connect */
00080     if (status() != Connecting) {
00081       vNotice("Cancelling attempt to connect to Tor's control port.");
00082       return false;
00083     }
00084     
00085     /* Try to connect */
00086     _connMutex.lock();
00087     vDebug("Control connection attempt %1 of %2").arg(i+1)
00088                                                   .arg(MAX_CONNECT_ATTEMPTS);
00089     result = _sock->connect(_addr, _port, &errmsg); 
00090     _connMutex.unlock();
00091     if (result) {
00092       vInfo("Connected to Tor's control port.");
00093       setStatus(Connected);
00094       emit connected();
00095       return true;
00096     }
00097     QThread::usleep(CONNECT_RETRY_DELAY);
00098   }
00099   setStatus(Disconnected);
00100   vWarn("Failed to connect to Tor's control port after %1 attempts: %2")
00101                                                       .arg(MAX_CONNECT_ATTEMPTS)
00102                                                       .arg(errmsg);
00103   emit connectFailed(errmsg);
00104   return false;
00105 }
00106 
00107 /** Disconnect from Tor's control interface. */
00108 void
00109 ControlConnection::disconnect()
00110 {
00111   /* Stop the event loop */
00112   exit(0);
00113 }
00114 
00115 /** Cancels a pending control connection to Tor. */
00116 void
00117 ControlConnection::cancelConnect()
00118 {
00119   QMutexLocker locker(&_connMutex);
00120   _status = Disconnected;
00121 }
00122 
00123 /** Returns the status of the control connection. */
00124 ControlConnection::Status
00125 ControlConnection::status()
00126 {
00127   QMutexLocker locker(&_connMutex);
00128   return _status;
00129 }
00130 
00131 /** Sets the control connection status. */
00132 void
00133 ControlConnection::setStatus(Status status)
00134 {
00135   QMutexLocker locker(&_connMutex);
00136   _status = status;
00137 }
00138 
00139 /** Sends a control command to Tor and waits for the reply. */
00140 bool
00141 ControlConnection::send(ControlCommand cmd, ControlReply &reply, QString *errmsg)
00142 {
00143   bool result = false;
00144   QString errstr;
00145 
00146   _recvMutex.lock();
00147   if (send(cmd, &errstr)) {
00148     /* Create and enqueue a new receive waiter */
00149     ReceiveWaiter *w = new ReceiveWaiter();
00150     _recvQueue.enqueue(w);
00151     _recvMutex.unlock();
00152 
00153     /* Wait for and get the result, clean up, and return */
00154     result = w->getResult(&reply, &errstr);
00155     if (!result)
00156       vWarn("Failed to receive control reply: %1").arg(errstr);
00157     delete w;
00158   } else {
00159     vWarn("Failed to send control command (%1): %2")
00160       .arg(cmd.keyword()).arg(errstr);
00161     _recvMutex.unlock();
00162   }
00163 
00164   if (!result && errmsg)
00165     *errmsg = errstr;
00166   return result;
00167 }
00168 
00169 /** Sends a control command to Tor. If the current thread is not the thread
00170  * that actually owns the socket, the command will be pushed to the correct
00171  * thread before sending. */
00172 bool
00173 ControlConnection::send(ControlCommand cmd, QString *errmsg)
00174 {
00175   QThread *socketThread;
00176   bool result;
00177 
00178   /* Check for a valid and connected socket */
00179   _connMutex.lock();
00180   if (!_sock || _status != Connected) {
00181     _connMutex.unlock();
00182     return err(errmsg, tr("Control socket is not connected."));
00183   }
00184   socketThread = _sock->thread();
00185   _connMutex.unlock();
00186 
00187   if (socketThread != QThread::currentThread()) {
00188     /* Push the message to the correct thread before sending */
00189     SendWaiter *w = new SendWaiter();
00190     Vidalia::postEvent(_sock, new SendCommandEvent(cmd, w));
00191   
00192     /* Wait for the result, clean up, and return */
00193     result = w->getResult(errmsg);
00194     delete w;
00195   } else {
00196     /* Send the command directly on the socket */
00197     _connMutex.lock();
00198     result = _sock->sendCommand(cmd, errmsg);
00199     _connMutex.unlock();
00200   }
00201   return result;
00202 }
00203 
00204 /** Called when there is data on the control socket. */
00205 void
00206 ControlConnection::onReadyRead()
00207 {
00208   QMutexLocker locker(&_connMutex);
00209   ReceiveWaiter *waiter;
00210   QString errmsg;
00211  
00212   while (_sock->canReadLine()) {
00213     ControlReply reply;
00214     if (_sock->readReply(reply, &errmsg)) {
00215       if (reply.getStatus() == "650") {
00216         /* Asynchronous event message */
00217         vDebug("Control Event: %1").arg(reply.toString());
00218         
00219         if (_events) {
00220           _events->handleEvent(reply);
00221         }
00222       } else {
00223         /* Response to a previous command */
00224         vInfo("Control Reply: %1").arg(reply.toString());
00225         
00226         _recvMutex.lock();
00227         if (!_recvQueue.isEmpty()) {
00228           waiter = _recvQueue.dequeue();
00229           waiter->setResult(true, reply);
00230         }
00231         _recvMutex.unlock();
00232       }
00233     } else {
00234       vWarn("Unable to read control reply: %1").arg(errmsg);
00235     }
00236   }
00237 }
00238 
00239 /** Catches events for the control socket. */
00240 bool
00241 ControlConnection::eventFilter(QObject *obj, QEvent *event)
00242 {
00243   if (event->type() == CustomEventType::SendCommandEvent) {
00244     /* Get the control command and waiter from the event */
00245     SendCommandEvent *sce = (SendCommandEvent *)event;
00246     SendWaiter *w = sce->waiter();
00247     QString errmsg;
00248     bool result;
00249     
00250     /* Send the command, if the socket exists. */
00251     _connMutex.lock();
00252     if (_sock) {
00253       result = _sock->sendCommand(sce->command(), &errmsg);
00254     } else {
00255       result = false;
00256       errmsg = tr("Control socket is not connected");
00257     }
00258     _connMutex.unlock();
00259     
00260     /* If there is someone waiting for a result, give them one. */
00261     if (w) {
00262       w->setResult(result, errmsg);
00263     }
00264 
00265     /* Stop processing this event */
00266     sce->accept();
00267     return true;
00268   }
00269   /* Pass other events on */
00270   return QObject::eventFilter(obj, event);
00271 }
00272 
00273 /** Main thread implementation. Creates and connects a control socket, then
00274  * spins up an event loop. */
00275 void
00276 ControlConnection::run()
00277 {
00278   /* Create a new control socket */
00279   _connMutex.lock();
00280   _sock = new ControlSocket();
00281   QObject::connect(_sock, SIGNAL(readyRead()), this, SLOT(onReadyRead()),
00282                    Qt::DirectConnection);
00283   QObject::connect(_sock, SIGNAL(disconnected()), this, SLOT(quit()),
00284                    Qt::DirectConnection);
00285   _sock->installEventFilter(this);
00286   _connMutex.unlock();
00287   
00288   /* Attempt to connect to Tor */
00289   if (connect()) {
00290     vDebug("Starting control connection event loop.");
00291     /* Kick off the event loop */
00292     exec();
00293     vDebug("Exited control connection event loop.");
00294   }
00295   
00296   /* Update the connection status */
00297   setStatus(Disconnected);
00298   emit disconnected();
00299 
00300   /* Clean up the socket */
00301   _connMutex.lock();
00302   QObject::disconnect(_sock, 0, 0, 0);
00303   delete _sock;
00304   _sock = 0;
00305   _connMutex.unlock();
00306 
00307   /* If there are any messages waiting for a response, clear them. */
00308   _recvMutex.lock();
00309   foreach (ReceiveWaiter *w, _recvQueue) {
00310     w->setResult(false, ControlReply(), 
00311                  tr("Control socket is not connected."));
00312   }
00313   _recvMutex.unlock();
00314 }
00315 
00316 
00317 /*
00318  * ControlConnection::ReceiveWaiter
00319  */
00320 /** Waits for and gets the reply from a control command. */
00321 bool 
00322 ControlConnection::ReceiveWaiter::getResult(ControlReply *reply, 
00323                                             QString *errmsg)
00324 {
00325   forever {
00326     _mutex.lock();
00327     if (_status == Waiting) {
00328       _waitCond.wait(&_mutex);
00329       _mutex.unlock();
00330     } else {
00331       _mutex.unlock();
00332       break;
00333     }
00334   }
00335   if (errmsg) {
00336     *errmsg = _errmsg;
00337   }
00338   *reply = _reply;
00339   return (_status == Success);
00340 }
00341 
00342 /** Sets the result and reply from a control command. */
00343 void 
00344 ControlConnection::ReceiveWaiter::setResult(bool success, 
00345                                             ControlReply reply, 
00346                                             QString errmsg)
00347 {
00348   _mutex.lock();
00349   _status = (success ? Success : Failed);
00350   _reply = reply; 
00351   _errmsg = errmsg;
00352   _mutex.unlock();
00353   _waitCond.wakeAll();
00354 }
00355 
00356 
00357 /*
00358  * ControlConnection::SendWaiter
00359  */
00360 /** Sets the result of the send operation. */
00361 void
00362 ControlConnection::SendWaiter::setResult(bool success, QString errmsg)
00363 {
00364   _mutex.lock();
00365   _status = (success ? Success : Failed);
00366   _errmsg = errmsg;
00367   _mutex.unlock();
00368   _waitCond.wakeAll();
00369 }
00370 
00371 /** Waits for and gets the result of the send operation. */
00372 bool 
00373 ControlConnection::SendWaiter::getResult(QString *errmsg)
00374 {
00375   forever {
00376     _mutex.lock();
00377     if (_status == Waiting) {
00378       _waitCond.wait(&_mutex);
00379       _mutex.unlock();
00380     } else {
00381       _mutex.unlock();
00382       break;
00383     }
00384   }
00385   if (errmsg) {
00386     *errmsg = _errmsg;
00387   }
00388   return (_status == Success);
00389 }
00390 

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