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 1250 2006-10-01 06:45:22Z 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       return false;
00082     }
00083     
00084     /* Try to connect */
00085     _connMutex.lock();
00086     result = _sock->connect(_addr, _port, &errmsg); 
00087     _connMutex.unlock();
00088     if (result) {
00089       setStatus(Connected);
00090       emit connected();
00091       return true;
00092     }
00093     QThread::usleep(CONNECT_RETRY_DELAY);
00094   }
00095   setStatus(Disconnected);
00096   emit connectFailed(errmsg);
00097   return false;
00098 }
00099 
00100 /** Disconnect from Tor's control interface. */
00101 void
00102 ControlConnection::disconnect()
00103 {
00104   /* Stop the event loop */
00105   exit(0);
00106 }
00107 
00108 /** Cancels a pending control connection to Tor. */
00109 void
00110 ControlConnection::cancelConnect()
00111 {
00112   QMutexLocker locker(&_connMutex);
00113   _status = Disconnected;
00114 }
00115 
00116 /** Returns the status of the control connection. */
00117 ControlConnection::Status
00118 ControlConnection::status()
00119 {
00120   QMutexLocker locker(&_connMutex);
00121   return _status;
00122 }
00123 
00124 /** Sets the control connection status. */
00125 void
00126 ControlConnection::setStatus(Status status)
00127 {
00128   QMutexLocker locker(&_connMutex);
00129   _status = status;
00130 }
00131 
00132 /** Sends a control command to Tor and waits for the reply. */
00133 bool
00134 ControlConnection::send(ControlCommand cmd, ControlReply &reply, QString *errmsg)
00135 {
00136   _recvMutex.lock();
00137   if (send(cmd, errmsg)) {
00138     /* Create and enqueue a new receive waiter */
00139     ReceiveWaiter *w = new ReceiveWaiter();
00140     _recvQueue.enqueue(w);
00141     _recvMutex.unlock();
00142 
00143     /* Wait for and get the result, clean up, and return */
00144     bool result = w->getResult(&reply, errmsg);
00145     delete w;
00146     return result;
00147   }
00148   _recvMutex.unlock();
00149   return false;
00150 }
00151 
00152 /** Sends a control command to Tor. If the current thread is not the thread
00153  * that actually owns the socket, the command will be pushed to the correct
00154  * thread before sending. */
00155 bool
00156 ControlConnection::send(ControlCommand cmd, QString *errmsg)
00157 {
00158   QThread *socketThread;
00159   bool result;
00160 
00161   /* Check for a valid and connected socket */
00162   _connMutex.lock();
00163   if (!_sock || _status != Connected) {
00164     _connMutex.unlock();
00165     return err(errmsg, tr("Control socket is not connected."));
00166   }
00167   socketThread = _sock->thread();
00168   _connMutex.unlock();
00169 
00170   if (socketThread != QThread::currentThread()) {
00171     /* Push the message to the correct thread before sending */
00172     SendWaiter *w = new SendWaiter();
00173     Vidalia::postEvent(_sock, new SendCommandEvent(cmd, w));
00174   
00175     /* Wait for the result, clean up, and return */
00176     result = w->getResult(errmsg);
00177     delete w;
00178   } else {
00179     /* Send the command directly on the socket */
00180     _connMutex.lock();
00181     result = _sock->sendCommand(cmd, errmsg);
00182     _connMutex.unlock();
00183   }
00184   return result;
00185 }
00186 
00187 /** Called when there is data on the control socket. */
00188 void
00189 ControlConnection::onReadyRead()
00190 {
00191   QMutexLocker locker(&_connMutex);
00192   ReceiveWaiter *waiter;
00193  
00194   while (_sock->canReadLine()) {
00195     ControlReply reply;
00196     if (_sock->readReply(reply)) {
00197       if (reply.getStatus() == "650") {
00198         /* Asynchronous event message */
00199         if (_events) {
00200           _events->handleEvent(reply);
00201         }
00202       } else {
00203         /* Response to a previous command */
00204         _recvMutex.lock();
00205         if (!_recvQueue.isEmpty()) {
00206           waiter = _recvQueue.dequeue();
00207           waiter->setResult(true, reply);
00208         }
00209         _recvMutex.unlock();
00210       }
00211     }
00212   }
00213 }
00214 
00215 /** Catches events for the control socket. */
00216 bool
00217 ControlConnection::eventFilter(QObject *obj, QEvent *event)
00218 {
00219   if (event->type() == CustomEventType::SendCommandEvent) {
00220     /* Get the control command and waiter from the event */
00221     SendCommandEvent *sce = (SendCommandEvent *)event;
00222     SendWaiter *w = sce->waiter();
00223     QString errmsg;
00224     bool result;
00225     
00226     /* Send the command, if the socket exists. */
00227     _connMutex.lock();
00228     if (_sock) {
00229       result = _sock->sendCommand(sce->command(), &errmsg);
00230     } else {
00231       result = false;
00232       errmsg = tr("Control socket is not connected");
00233     }
00234     _connMutex.unlock();
00235     
00236     /* If there is someone waiting for a result, give them one. */
00237     if (w) {
00238       w->setResult(result, errmsg);
00239     }
00240 
00241     /* Stop processing this event */
00242     sce->accept();
00243     return true;
00244   }
00245   /* Pass other events on */
00246   return QObject::eventFilter(obj, event);
00247 }
00248 
00249 /** Main thread implementation. Creates and connects a control socket, then
00250  * spins up an event loop. */
00251 void
00252 ControlConnection::run()
00253 {
00254   /* Create a new control socket */
00255   _connMutex.lock();
00256   _sock = new ControlSocket();
00257   QObject::connect(_sock, SIGNAL(readyRead()), this, SLOT(onReadyRead()),
00258                    Qt::DirectConnection);
00259   _sock->installEventFilter(this);
00260   _connMutex.unlock();
00261   
00262   /* Attempt to connect to Tor */
00263   if (connect()) {
00264     /* Kick off the event loop */
00265     exec();
00266   }
00267   
00268   /* Update the connection status */
00269   setStatus(Disconnected);
00270   emit disconnected();
00271 
00272   /* Clean up the socket */
00273   _connMutex.lock();
00274   QObject::disconnect(_sock, 0, 0, 0);
00275   delete _sock;
00276   _sock = 0;
00277   _connMutex.unlock();
00278 
00279   /* If there are any messages waiting for a response, clear them. */
00280   _recvMutex.lock();
00281   foreach (ReceiveWaiter *w, _recvQueue) {
00282     w->setResult(false, ControlReply(), 
00283                  tr("Control socket is not connected."));
00284   }
00285   _recvMutex.unlock();
00286 }
00287 
00288 
00289 /*
00290  * ControlConnection::ReceiveWaiter
00291  */
00292 /** Waits for and gets the reply from a control command. */
00293 bool 
00294 ControlConnection::ReceiveWaiter::getResult(ControlReply *reply, 
00295                                             QString *errmsg)
00296 {
00297   forever {
00298     _mutex.lock();
00299     if (_status == Waiting) {
00300       _waitCond.wait(&_mutex);
00301       _mutex.unlock();
00302     } else {
00303       _mutex.unlock();
00304       break;
00305     }
00306   }
00307   if (errmsg) {
00308     *errmsg = _errmsg;
00309   }
00310   *reply = _reply;
00311   return (_status == Success);
00312 }
00313 
00314 /** Sets the result and reply from a control command. */
00315 void 
00316 ControlConnection::ReceiveWaiter::setResult(bool success, 
00317                                             ControlReply reply, 
00318                                             QString errmsg)
00319 { 
00320   _status = (success ? Success : Failed);
00321   _reply = reply; 
00322   _errmsg = errmsg;
00323   _waitCond.wakeAll();
00324 
00325 }
00326 
00327 
00328 /*
00329  * ControlConnection::SendWaiter
00330  */
00331 /** Sets the result of the send operation. */
00332 void
00333 ControlConnection::SendWaiter::setResult(bool success, QString errmsg)
00334 {
00335   _mutex.lock();
00336   _status = (success ? Success : Failed);
00337   _errmsg = errmsg;
00338   _mutex.unlock();
00339   _waitCond.wakeAll();
00340 }
00341 
00342 /** Waits for and gets the result of the send operation. */
00343 bool 
00344 ControlConnection::SendWaiter::getResult(QString *errmsg)
00345 {
00346   forever {
00347     _mutex.lock();
00348     if (_status == Waiting) {
00349       _waitCond.wait(&_mutex);
00350       _mutex.unlock();
00351     } else {
00352       _mutex.unlock();
00353       break;
00354     }
00355   }
00356   if (errmsg) {
00357     *errmsg = _errmsg;
00358   }
00359   return (_status == Success);
00360 }
00361 

Generated on Mon Oct 23 20:08:15 2006 for Vidalia by  doxygen 1.5.0