[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[vidalia-svn] r1250: Run an event loop in our thread that waits for asynchronous (trunk/src/control)
Author: edmanm
Date: 2006-10-01 02:45:22 -0400 (Sun, 01 Oct 2006)
New Revision: 1250
Modified:
trunk/src/control/controlconnection.cpp
trunk/src/control/controlconnection.h
trunk/src/control/controlsocket.cpp
trunk/src/control/controlsocket.h
trunk/src/control/eventtype.h
Log:
Run an event loop in our thread that waits for asynchronous events from Tor,
instead of essentially blocking waiting for events (Ticket #101). This is a
big change to a critical component. hipplej, please review, test, check for
rabies, etc.
Modified: trunk/src/control/controlconnection.cpp
===================================================================
--- trunk/src/control/controlconnection.cpp 2006-09-30 17:33:01 UTC (rev 1249)
+++ trunk/src/control/controlconnection.cpp 2006-10-01 06:45:22 UTC (rev 1250)
@@ -26,62 +26,91 @@
* receiving commands and events
*/
-#include <QCoreApplication>
+#include <QMutexLocker>
#include <util/string.h>
+#include <vidalia.h>
#include "controlconnection.h"
-
-/** Maximum time to wait for new data to arrive on the socket. */
-#define WAIT_TIMEOUT 10
/** Maximum number of times we'll try to connect to Tor before giving up.*/
#define MAX_CONNECT_ATTEMPTS 6
/** Time to wait between control connection attempts (in microseconds). */
#define CONNECT_RETRY_DELAY 500*1000
-/** Constructor.
- * \param events a TorEvents object used to dispatch asynchronous events
- * received from Tor.
- */
+/** Default constructor. */
ControlConnection::ControlConnection(TorEvents *events)
{
_events = events;
- _run = false;
- _status = Disconnected;
+ _sock = 0;
}
-/** Connects to Tor's control interface and starts a thread used to process
- * asynchronous event messages received from Tor. All socket communication is
- * done in the new thread, processing incoming and outgoing messages through the
- * send and receive queues.
- * \param addr IP address of Tor's control interface.
- * \param port port of Tor's control interface.
- * \param errmsg Stores an error message if the connection fails.
- * \return true if a connection to Tor's control interface was successfully
- * established. Otherwise, returns false and sets errmsg.
- * */
+/** Destructor. */
+ControlConnection::~ControlConnection()
+{
+ /* Exit the event loop */
+ exit();
+ /* Wait for the thread to finish. */
+ wait();
+}
+
+/** Connect to the specified Tor control interface. */
void
ControlConnection::connect(QHostAddress addr, quint16 port)
{
- /* Store the control interface address information */
+ /* Save the destination information */
_addr = addr;
_port = port;
- _run = true;
- _status = Disconnected;
- _cancelConnect = false;
-
- /* Start a thread. Either connected() or connectFailed() will be emitted
- * once the connection attempt has completed. */
+ /* Kick off the thread in which the control socket will live */
QThread::start();
}
-/** Cancels a pending connection attempt. */
+/** Attempt to establish a connection to Tor's control interface. We will try
+* a maximum of MAX_CONNECT_ATTEMPTS, waiting CONNECT_RETRY_DELAY between each
+* attempt, to give slow Tors a chance to finish binding their control port. */
+bool
+ControlConnection::connect()
+{
+ QString errmsg;
+ bool result;
+
+ setStatus(Connecting);
+ for (int i = 0; i < MAX_CONNECT_ATTEMPTS; i++) {
+ /* Check if we're supposed to cancel our attempt to connect */
+ if (status() != Connecting) {
+ return false;
+ }
+
+ /* Try to connect */
+ _connMutex.lock();
+ result = _sock->connect(_addr, _port, &errmsg);
+ _connMutex.unlock();
+ if (result) {
+ setStatus(Connected);
+ emit connected();
+ return true;
+ }
+ QThread::usleep(CONNECT_RETRY_DELAY);
+ }
+ setStatus(Disconnected);
+ emit connectFailed(errmsg);
+ return false;
+}
+
+/** Disconnect from Tor's control interface. */
void
+ControlConnection::disconnect()
+{
+ /* Stop the event loop */
+ exit(0);
+}
+
+/** Cancels a pending control connection to Tor. */
+void
ControlConnection::cancelConnect()
{
QMutexLocker locker(&_connMutex);
- _cancelConnect = true;
+ _status = Disconnected;
}
/** Returns the status of the control connection. */
@@ -89,16 +118,10 @@
ControlConnection::status()
{
QMutexLocker locker(&_connMutex);
- if (_status == Connected) {
- /* The thread must be running for us to be considered connected */
- if (!_run || !isRunning()) {
- return Disconnected;
- }
- }
return _status;
}
-/** Sets the status of the control connection. */
+/** Sets the control connection status. */
void
ControlConnection::setStatus(Status status)
{
@@ -106,150 +129,71 @@
_status = status;
}
-/** Disconnects the control socket and stops all message processing. */
-void
-ControlConnection::disconnect()
+/** Sends a control command to Tor and waits for the reply. */
+bool
+ControlConnection::send(ControlCommand cmd, ControlReply &reply, QString *errmsg)
{
- /* Check if we're already disconnected */
- if (status() != Connected) {
- return;
- }
- _run = false;
-}
+ _recvMutex.lock();
+ if (send(cmd, errmsg)) {
+ /* Create and enqueue a new receive waiter */
+ ReceiveWaiter *w = new ReceiveWaiter();
+ _recvQueue.enqueue(w);
+ _recvMutex.unlock();
-/** Flushes any outstanding waiters in the send or receive queues. */
-void
-ControlConnection::flushQueues()
-{
- /* Flush any outstanding waiters in the send queue */
- _sendMutex.lock();
- while (!_sendQueue.isEmpty()) {
- SendWaiter *waiter = _sendQueue.dequeue();
- waiter->setResult(Failed, tr("The control socket is closing."));
+ /* Wait for and get the result, clean up, and return */
+ bool result = w->getResult(&reply, errmsg);
+ delete w;
+ return result;
}
- _sendMutex.unlock();
-
- /* Flush any outstanding waiters in the receive queue */
- _recvMutex.lock();
- while (!_recvQueue.isEmpty()) {
- ReceiveWaiter *waiter = _recvQueue.dequeue();
- waiter->setResult(Failed, ControlReply(),
- tr("The control socket is closing."));
- }
_recvMutex.unlock();
+ return false;
}
-/** Sends a control command to Tor and does not wait for a reply. */
+/** Sends a control command to Tor. If the current thread is not the thread
+ * that actually owns the socket, the command will be pushed to the correct
+ * thread before sending. */
bool
ControlConnection::send(ControlCommand cmd, QString *errmsg)
{
- QWaitCondition waitCond;
- SendWaiter sendWaiter(cmd, &waitCond);
-
- /* Make sure we have a valid control socket before trying to send. */
- if (status() != Connected) {
- return err(errmsg, tr("Control socket not connected."));
- }
-
- /* Add a send waiter to the outgoing message queue */
- _sendMutex.lock();
- _sendQueue.enqueue(&sendWaiter);
- waitCond.wait(&_sendMutex);
- _sendMutex.unlock();
+ QThread *socketThread;
+ bool result;
- /* Check if the send failed. */
- if (sendWaiter.status() == Failed) {
- return err(errmsg, sendWaiter.errorString());
+ /* Check for a valid and connected socket */
+ _connMutex.lock();
+ if (!_sock || _status != Connected) {
+ _connMutex.unlock();
+ return err(errmsg, tr("Control socket is not connected."));
}
- return true;
-}
+ socketThread = _sock->thread();
+ _connMutex.unlock();
-/** Sends a control command to Tor and waits for the response.
- * \param cmd The command to send to Tor.
- * \param reply The response from Tor.
- * \param errmsg Stores an error message if the send or receive failed.
- * \return true if the command was sent and a response was received.
- */
-bool
-ControlConnection::send(ControlCommand cmd, ControlReply &reply, QString *errmsg)
-{
- QWaitCondition waitCond;
- SendWaiter sendWaiter(cmd, &waitCond);
- ReceiveWaiter recvWaiter(&reply, &waitCond);
+ if (socketThread != QThread::currentThread()) {
+ /* Push the message to the correct thread before sending */
+ SendWaiter *w = new SendWaiter();
+ Vidalia::postEvent(_sock, new SendCommandEvent(cmd, w));
- /* Make sure we have a valid control socket before trying to send. */
- if (status() != Connected) {
- return err(errmsg, tr("Control socket not connected."));
+ /* Wait for the result, clean up, and return */
+ result = w->getResult(errmsg);
+ delete w;
+ } else {
+ /* Send the command directly on the socket */
+ _connMutex.lock();
+ result = _sock->sendCommand(cmd, errmsg);
+ _connMutex.unlock();
}
-
- /* Add a send waiter to the outgoing message queue */
- _sendMutex.lock();
- _sendQueue.enqueue(&sendWaiter);
-
- /* Lock the receive mutex and wait for the message to be sent. The receive
- * mutex is locked so the response doesn't get added to the incoming message
- * queue before we have a waiter for it, but we don't add a waiter yet
- * because if the send fails, then no response will ever be received. */
- _recvMutex.lock();
- waitCond.wait(&_sendMutex);
- _sendMutex.unlock();
-
- /* Check if the send failed. */
- if (sendWaiter.status() == Failed) {
- _recvMutex.unlock();
- return err(errmsg, sendWaiter.errorString());
- }
-
- /* The send was successful, so add a waiter for the response. */
- _recvQueue.enqueue(&recvWaiter);
- waitCond.wait(&_recvMutex);
- _recvMutex.unlock();
-
- /* If the receive failed, then get the error string */
- if (recvWaiter.status() == Failed) {
- return err(errmsg, recvWaiter.errorString());
- }
- return true;
+ return result;
}
-/** Determines if there are any messages waiting in the outgoing message queue.
- * \return true if the send queue is empty.
- */
-bool
-ControlConnection::isSendQueueEmpty()
-{
- QMutexLocker locker(&_sendMutex);
- return _sendQueue.isEmpty();
-}
-
-/** Processes any messages waiting in the send queue. */
+/** Called when there is data on the control socket. */
void
-ControlConnection::processSendQueue(ControlSocket *sock)
+ControlConnection::onReadyRead()
{
- SendWaiter *sendWaiter;
- bool result;
- QString errorString;
+ QMutexLocker locker(&_connMutex);
+ ReceiveWaiter *waiter;
- /* Iterate through all messages waiting in the queue */
- _sendMutex.lock();
- while (!_sendQueue.isEmpty()) {
- /* Grab a waiter, try to send it, and store the result */
- sendWaiter = _sendQueue.dequeue();
- result = sock->sendCommand(sendWaiter->command(), &errorString);
- sendWaiter->setResult((result ? Success : Failed), errorString);
- }
- _sendMutex.unlock();
-}
-
-/** Processes any messages waiting on the control socket. */
-void
-ControlConnection::processReceiveQueue(ControlSocket *sock)
-{
- ReceiveWaiter *waiter;
-
- while (sock->canReadLine()) {
+ while (_sock->canReadLine()) {
ControlReply reply;
- if (sock->readReply(reply)) {
+ if (_sock->readReply(reply)) {
if (reply.getStatus() == "650") {
/* Asynchronous event message */
if (_events) {
@@ -260,7 +204,7 @@
_recvMutex.lock();
if (!_recvQueue.isEmpty()) {
waiter = _recvQueue.dequeue();
- waiter->setResult(Success, reply);
+ waiter->setResult(true, reply);
}
_recvMutex.unlock();
}
@@ -268,75 +212,150 @@
}
}
-/** Attempt to establish a connection to Tor's control interface. We will try
- * a maximum of MAX_CONNECT_ATTEMPTS, waiting CONNECT_RETRY_DELAY between each
- * attempt, to give slow Tors a chance to finish binding their control port. */
+/** Catches events for the control socket. */
bool
-ControlConnection::connect(ControlSocket *sock, QString *errmsg)
+ControlConnection::eventFilter(QObject *obj, QEvent *event)
{
- setStatus(Connecting);
- for (int i = 0; i < MAX_CONNECT_ATTEMPTS; i++) {
- /* Check if we're supposed to cancel our attempt to connect */
+ if (event->type() == CustomEventType::SendCommandEvent) {
+ /* Get the control command and waiter from the event */
+ SendCommandEvent *sce = (SendCommandEvent *)event;
+ SendWaiter *w = sce->waiter();
+ QString errmsg;
+ bool result;
+
+ /* Send the command, if the socket exists. */
_connMutex.lock();
- if (_cancelConnect) {
- _connMutex.unlock();
- return false;
+ if (_sock) {
+ result = _sock->sendCommand(sce->command(), &errmsg);
+ } else {
+ result = false;
+ errmsg = tr("Control socket is not connected");
}
_connMutex.unlock();
- /* Try to connect */
- if (sock->connect(_addr, _port, errmsg)) {
- return true;
+ /* If there is someone waiting for a result, give them one. */
+ if (w) {
+ w->setResult(result, errmsg);
}
- QThread::usleep(CONNECT_RETRY_DELAY);
+
+ /* Stop processing this event */
+ sce->accept();
+ return true;
}
- return false;
+ /* Pass other events on */
+ return QObject::eventFilter(obj, event);
}
-/** Main thread implementation. Creates and connects a control socket and
- * processes any messages either waiting to be sent or waiting to be read off
- * the control socket, until either disconnect() is called or the socket gets
- * disconnected through some other means. */
+/** Main thread implementation. Creates and connects a control socket, then
+ * spins up an event loop. */
void
ControlConnection::run()
{
- QString errmsg;
+ /* Create a new control socket */
+ _connMutex.lock();
+ _sock = new ControlSocket();
+ QObject::connect(_sock, SIGNAL(readyRead()), this, SLOT(onReadyRead()),
+ Qt::DirectConnection);
+ _sock->installEventFilter(this);
+ _connMutex.unlock();
- /* Create a new control socket and try to connect to Tor */
- ControlSocket *sock = new ControlSocket();
+ /* Attempt to connect to Tor */
+ if (connect()) {
+ /* Kick off the event loop */
+ exec();
+ }
- if (!connect(sock, &errmsg)) {
- if (!_cancelConnect) {
- /* If the connect failed and wasn't cancelled, then emit the error */
- emit connectFailed(errmsg);
+ /* Update the connection status */
+ setStatus(Disconnected);
+ emit disconnected();
+
+ /* Clean up the socket */
+ _connMutex.lock();
+ QObject::disconnect(_sock, 0, 0, 0);
+ delete _sock;
+ _sock = 0;
+ _connMutex.unlock();
+
+ /* If there are any messages waiting for a response, clear them. */
+ _recvMutex.lock();
+ foreach (ReceiveWaiter *w, _recvQueue) {
+ w->setResult(false, ControlReply(),
+ tr("Control socket is not connected."));
+ }
+ _recvMutex.unlock();
+}
+
+
+/*
+ * ControlConnection::ReceiveWaiter
+ */
+/** Waits for and gets the reply from a control command. */
+bool
+ControlConnection::ReceiveWaiter::getResult(ControlReply *reply,
+ QString *errmsg)
+{
+ forever {
+ _mutex.lock();
+ if (_status == Waiting) {
+ _waitCond.wait(&_mutex);
+ _mutex.unlock();
+ } else {
+ _mutex.unlock();
+ break;
}
- } else {
- setStatus(Connected);
- emit connected();
- while (_run && sock->isConnected()) {
- /* If there are messages in the send queue, then send them */
- if (!isSendQueueEmpty()) {
- processSendQueue(sock);
- }
-
- /* Wait for some data to appear on the socket */
- sock->waitForReadyRead(WAIT_TIMEOUT);
-
- /* If there are messages waiting on the socket, read them in */
- if (sock->bytesAvailable()) {
- processReceiveQueue(sock);
- }
+ }
+ if (errmsg) {
+ *errmsg = _errmsg;
+ }
+ *reply = _reply;
+ return (_status == Success);
+}
+
+/** Sets the result and reply from a control command. */
+void
+ControlConnection::ReceiveWaiter::setResult(bool success,
+ ControlReply reply,
+ QString errmsg)
+{
+ _status = (success ? Success : Failed);
+ _reply = reply;
+ _errmsg = errmsg;
+ _waitCond.wakeAll();
+
+}
+
+
+/*
+ * ControlConnection::SendWaiter
+ */
+/** Sets the result of the send operation. */
+void
+ControlConnection::SendWaiter::setResult(bool success, QString errmsg)
+{
+ _mutex.lock();
+ _status = (success ? Success : Failed);
+ _errmsg = errmsg;
+ _mutex.unlock();
+ _waitCond.wakeAll();
+}
+
+/** Waits for and gets the result of the send operation. */
+bool
+ControlConnection::SendWaiter::getResult(QString *errmsg)
+{
+ forever {
+ _mutex.lock();
+ if (_status == Waiting) {
+ _waitCond.wait(&_mutex);
+ _mutex.unlock();
+ } else {
+ _mutex.unlock();
+ break;
}
- if (sock->isConnected()) {
- sock->disconnect();
- }
- emit disconnected();
-
- /* Flush the send and receive queues. */
- flushQueues();
}
- setStatus(Disconnected);
- _run = false;
- delete sock;
+ if (errmsg) {
+ *errmsg = _errmsg;
+ }
+ return (_status == Success);
}
Modified: trunk/src/control/controlconnection.h
===================================================================
--- trunk/src/control/controlconnection.h 2006-09-30 17:33:01 UTC (rev 1249)
+++ trunk/src/control/controlconnection.h 2006-10-01 06:45:22 UTC (rev 1250)
@@ -2,7 +2,7 @@
* Vidalia is distributed under the following license:
*
* Copyright (C) 2006, Matt Edman, Justin Hipple
- *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -34,10 +34,11 @@
#include <QQueue>
#include <QWaitCondition>
+#include "eventtype.h"
#include "controlsocket.h"
#include "torevents.h"
-
+
class ControlConnection : public QThread
{
Q_OBJECT
@@ -52,18 +53,20 @@
/** Default constructor. */
ControlConnection(TorEvents *events = 0);
+ /** Destructor. */
+ ~ControlConnection();
/** Connect to the specified Tor control interface. */
void connect(QHostAddress addr, quint16 port);
- /** Cancels a pending connection to Tor. */
+ /** Cancels a pending control connection to Tor. */
void cancelConnect();
- /** Disconnect from Tor. */
+ /** Disconnect from Tor's control interface. */
void disconnect();
/** Returns the status of the control connection. */
Status status();
- /** Sends a control command to Tor and waits for the response. */
+ /** Sends a control command to Tor and waits for the reply. */
bool send(ControlCommand cmd, ControlReply &reply, QString *errmsg = 0);
- /** Sends a control command to Tor and does not wait for the response. */
+ /** Sends a control command to Tor and does not wait for a reply. */
bool send(ControlCommand cmd, QString *errmsg = 0);
signals:
@@ -74,87 +77,82 @@
/** Emitted when a control connection fails. */
void connectFailed(QString errmsg);
+protected:
+ /** Catches events for the control socket. */
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private slots:
+ /** Called when there is data on the control socket. */
+ void onReadyRead();
+
private:
+ /** Sets the control connection status. */
+ void setStatus(Status status);
+ /** Connects to Tor's control interface. */
+ bool connect();
/** Main thread implementation. */
void run();
- /** Connections the given socket to Tor. */
- bool connect(ControlSocket *socket, QString *errmsg);
- /** Checks if there are any outoing messages waiting. */
- bool isSendQueueEmpty();
- /** Processes any messages waiting to be sent. */
- void processSendQueue(ControlSocket *sock);
- /** Processes any messages waiting on the control socket. */
- void processReceiveQueue(ControlSocket *sock);
- /** Flushes any outstanding waiters in the send or receive queues. */
- void flushQueues();
- /** Sets the control connection status */
- void setStatus(Status status);
- Status _status; /**< The status of the control connection. */
- QHostAddress _addr; /**< Address of Tor's control interface. */
- quint16 _port; /**< Port of Tor's control interface. */
- QMutex _sendMutex; /**< Mutex for the send queue. */
- QMutex _recvMutex; /**< Mutex for the receive queue. */
- QMutex _connMutex; /**< Mutex for the status of the connection. */
- bool _cancelConnect; /**< Set to true when we cancel a pending connect. */
- /** Set to false when we are to disconnect and stop processing messages. */
- bool _run;
- /** Pointer to a previously constructed TorEvents list of event handlers */
- TorEvents* _events;
+ ControlSocket* _sock; /**< Socket used to communicate with Tor. */
+ TorEvents* _events; /**< Dispatches asynchronous events from Tor. */
+ Status _status; /**< Status of the control connection. */
+ QHostAddress _addr; /**< Address of Tor's control interface. */
+ quint16 _port; /**< Port of Tor's control interface. */
+ QMutex _connMutex; /**< Mutex around the control socket. */
+ QMutex _recvMutex; /**< Mutex around the queue of ReceiveWaiters. */
-
- /** Status of a message in either the send or receive queue */
- enum WaiterStatus {
- Waiting, /**< Message is still in the queue. */
- Failed, /**< The send or receive operation failed. */
- Success /**< The send or receive operation completed successfully. */
+ /** Private class used to wait for a response to a control command. */
+ class ReceiveWaiter {
+ public:
+ /** Default constructor. */
+ ReceiveWaiter() { _status = Waiting; }
+ /** Waits for and gets the reply from a control command. */
+ bool getResult(ControlReply *reply, QString *errmsg = 0);
+ /** Sets the result and reply from a control command. */
+ void setResult(bool success, ControlReply reply,
+ QString errmsg = QString());
+ private:
+ /** Status of the receive waiter. */
+ enum ReceiveStatus { Waiting, Failed, Success } _status;
+ ControlReply _reply; /**< Reply to a previous command. */
+ QMutex _mutex; /**< Mutex around the wait condition. */
+ QWaitCondition _waitCond; /**< Waits for a control rpely. */
+ QString _errmsg; /**< Error message if the reply fails. */
};
-
- /** An item in the send queue. */
- class SendWaiter
- {
+ QQueue<ReceiveWaiter *> _recvQueue; /**< Objects waiting for a reply. */
+
+ /** Object used to wait for the result of a send operation. */
+ class SendWaiter {
public:
- /** Create a new item for the send queue. */
- SendWaiter(ControlCommand cmd, QWaitCondition *waitCond)
- { _command = cmd; _status = Waiting; _waitCond = waitCond; }
- /** Gets the command waiting to be sent. */
- ControlCommand command() { return _command; }
- /** Gets the status of this item in the queue. */
- WaiterStatus status() { return _status; }
- /** Returns an error message if the send failed. */
- QString errorString() { return _errmsg; }
- /** Sets the result of sending an item in the send queue. */
- void setResult(WaiterStatus status, QString errmsg = QString())
- { _status = status; _errmsg = errmsg; _waitCond->wakeAll(); }
+ /** Default constructor. */
+ SendWaiter() { _status = Waiting; }
+ /** Sets the result of the send operation. */
+ void setResult(bool success, QString errmsg = QString());
+ /** Waits for and gets the result of the send operation. */
+ bool getResult(QString *errmsg = 0);
private:
- ControlCommand _command; /**< The command to send. */
- QWaitCondition* _waitCond; /**< Waits for a command to be sent. */
- WaiterStatus _status; /**< The status of this queue item. */
- QString _errmsg; /**< An error message if the send failed. */
+ /** Status of the send waiter. */
+ enum SenderStatus { Waiting, Failed, Success } _status;
+ QMutex _mutex; /**< Mutex around the wait condition. */
+ QWaitCondition _waitCond; /**< Waits for the send to complete. */
+ QString _errmsg; /**< Error message if the send fails. */
};
- QQueue<SendWaiter *> _sendQueue; /** Queue of commands waiting to be sent. */
-
- /** An item in the receive queue. */
- class ReceiveWaiter
- {
+
+ /** Private event used to push a control command to the socket's thread */
+ class SendCommandEvent : public QEvent {
public:
- /** Create a new item for the receive queue. */
- ReceiveWaiter(ControlReply *reply, QWaitCondition *waitCond)
- { _reply = reply; _status = Waiting; _waitCond = waitCond; }
- /** Gets the status of this item in the queue. */
- WaiterStatus status() { return _status; }
- /** Returns an error message if the receive failed. */
- QString errorString() { return _errmsg; }
- /** Sets the result of waiting for a control response. */
- void setResult(WaiterStatus status, ControlReply reply, QString errmsg = QString())
- { _status = status; *_reply = reply; _errmsg = errmsg; _waitCond->wakeAll(); }
+ /** Constructor. */
+ SendCommandEvent(ControlCommand cmd, SendWaiter *waiter = 0)
+ : QEvent((QEvent::Type)CustomEventType::SendCommandEvent)
+ { _cmd = cmd; _waiter = waiter; }
+ /** Returns the control command to send to Tor. */
+ ControlCommand command() { return _cmd; }
+ /** Returns a waiter (if any) for the result of this send. */
+ SendWaiter* waiter() { return _waiter; }
private:
- ControlReply* _reply; /**< The response received */
- QWaitCondition* _waitCond; /**< Waits for a reply to be received. */
- WaiterStatus _status; /**< The status of this queue item. */
- QString _errmsg; /**< An error message if the receive failed. */
+ ControlCommand _cmd; /**< Command to send to Tor. */
+ SendWaiter* _waiter; /**< Waiter for the result of this event. */
};
- QQueue<ReceiveWaiter *> _recvQueue; /** Queue of waiters for a response. */
};
#endif
Modified: trunk/src/control/controlsocket.cpp
===================================================================
--- trunk/src/control/controlsocket.cpp 2006-09-30 17:33:01 UTC (rev 1249)
+++ trunk/src/control/controlsocket.cpp 2006-10-01 06:45:22 UTC (rev 1250)
@@ -30,7 +30,16 @@
#include "controlsocket.h"
+/** Give up after waiting five seconds for the control socket to connect to
+* Tor. This timeout used to be shorter (three seconds), but some Agnitum
+* OutPost users yelled at us wanting a longer timeout, for some reason. */
+#define CONN_TIMEOUT 5000
+/** Timeout reads in 250ms. We can set this to a short value because if there
+* isn't any data to read, we want to return anyway. */
+#define READ_TIMEOUT 250
+
+
/** Default constructor. */
ControlSocket::ControlSocket()
{
@@ -58,7 +67,9 @@
}
/* Verify that Tor is speaking a protocol version we understand. */
+ blockSignals(true);
version = protocolVersion();
+ blockSignals(false);
if (version != Version1) {
if (errmsg) {
*errmsg =
@@ -132,7 +143,7 @@
ControlSocket::sendCommand(ControlCommand cmd, QString *errmsg)
{
if (!isConnected()) {
- return false;
+ return err(errmsg, tr("Control socket is not connected."));
}
/* Format the control command */
@@ -140,11 +151,8 @@
/* Attempt to send the command to Tor */
if (write(strCmd.toAscii()) != strCmd.length()) {
- if (errmsg) {
- *errmsg =
- tr("Error sending control command. [%1]").arg(errorString());
- }
- return false;
+ return err(errmsg, tr("Error sending control command. [%1]")
+ .arg(errorString()));
}
flush();
return true;
Modified: trunk/src/control/controlsocket.h
===================================================================
--- trunk/src/control/controlsocket.h 2006-09-30 17:33:01 UTC (rev 1249)
+++ trunk/src/control/controlsocket.h 2006-10-01 06:45:22 UTC (rev 1250)
@@ -34,16 +34,7 @@
#include "controlcommand.h"
#include "controlreply.h"
-/** Give up after waiting five seconds for the control socket to connect to
- * Tor. This timeout used to be shorter (three seconds), but some Agnitum
- * OutPost users yelled at us wanting a longer timeout, for some reason. */
-#define CONN_TIMEOUT 5000
-/** Timeout reads in 250ms. We can set this to a short value because if there
- * isn't any data to read, we want to return anyway. */
-#define READ_TIMEOUT 250
-
-
class ControlSocket : public QTcpSocket
{
Q_OBJECT
@@ -71,7 +62,7 @@
bool readLineData(QString &line, QString *errmsg = 0);
/** Reads a line of data from the socket (blocking) */
bool readLine(QString &line, QString *errmsg = 0);
-
+
private:
/** Specifies a version of Tor's Control Protocol */
enum ProtocolVersion {
Modified: trunk/src/control/eventtype.h
===================================================================
--- trunk/src/control/eventtype.h 2006-09-30 17:33:01 UTC (rev 1249)
+++ trunk/src/control/eventtype.h 2006-10-01 06:45:22 UTC (rev 1250)
@@ -30,13 +30,23 @@
#include <QEvent>
+
+/** Custom event type identifiers. */
namespace CustomEventType {
+ /** Bandwidth update event. */
const int BandwidthEvent = QEvent::User;
+ /** Circuit status event. */
const int CircuitEvent = QEvent::User+1;
+ /** Stream status event. */
const int StreamEvent = QEvent::User+2;
+ /** Log message event. */
const int LogEvent = QEvent::User+3;
+ /** OR connection status event. */
const int OrConnEvent = QEvent::User+4;
+ /** New descriptor event. */
const int NewDescriptorEvent = QEvent::User+5;
+ /** Control command send event. */
+ const int SendCommandEvent = QEvent::User+6;
}
#endif