Vidalia
0.2.17
|
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