commit ece9744a678d5601fcf76a2cbb668a88422c75eb
Author: Tomás Touceda <chiiph(a)torproject.org>
Date: Fri Jun 29 21:50:37 2012 -0300
Display stream traffic in the Circuit list in the Network Map
---
src/torcontrol/Stream.cpp | 4 +-
src/torcontrol/Stream.h | 1 +
src/torcontrol/TorControl.cpp | 2 +
src/torcontrol/TorControl.h | 8 +++++
src/torcontrol/TorEvents.cpp | 26 ++++++++++++++++
src/torcontrol/TorEvents.h | 46 ++++++++++++++++++----------
src/vidalia/network/CircuitListWidget.cpp | 19 ++++++++++-
src/vidalia/network/CircuitListWidget.h | 6 +++-
src/vidalia/network/NetViewer.cpp | 4 ++
src/vidalia/network/NetViewer.ui | 23 ++++++++++++--
src/vidalia/network/StreamItem.cpp | 34 +++++++++++++++++++++
src/vidalia/network/StreamItem.h | 7 ++++
12 files changed, 154 insertions(+), 26 deletions(-)
diff --git a/src/torcontrol/Stream.cpp b/src/torcontrol/Stream.cpp
index 7322d48..6f75bc0 100644
--- a/src/torcontrol/Stream.cpp
+++ b/src/torcontrol/Stream.cpp
@@ -88,8 +88,8 @@ Stream::isValidStreamId(const StreamId &streamId)
return false;
for (int i = 0; i < length; i++) {
- char c = streamId[i].toAscii();
- if (c < '0' && c > '9' && c < 'A' && c > 'Z' && c < 'a' && c > 'z')
+ QChar c = streamId[i];
+ if (!c.isLower() and !c.isUpper() and !c.isNumber())
return false;
}
return true;
diff --git a/src/torcontrol/Stream.h b/src/torcontrol/Stream.h
index f688391..8f1dfb0 100644
--- a/src/torcontrol/Stream.h
+++ b/src/torcontrol/Stream.h
@@ -26,6 +26,7 @@
/** Stream IDs contains 1-16 alphanumeric ASCII characters. */
typedef QString StreamId;
+Q_DECLARE_METATYPE(StreamId)
class Stream
diff --git a/src/torcontrol/TorControl.cpp b/src/torcontrol/TorControl.cpp
index c9893ce..01bfb1d 100644
--- a/src/torcontrol/TorControl.cpp
+++ b/src/torcontrol/TorControl.cpp
@@ -41,6 +41,8 @@ TorControl::TorControl(ControlMethod::Method method)
RELAY_SIGNAL(_eventHandler, SIGNAL(bandwidthUpdate(quint64, quint64)));
RELAY_SIGNAL(_eventHandler, SIGNAL(circuitStatusChanged(Circuit)));
RELAY_SIGNAL(_eventHandler, SIGNAL(streamStatusChanged(Stream)));
+ RELAY_SIGNAL(_eventHandler,
+ SIGNAL(streamBandwidthUpdate(StreamId, quint64, quint64)));
RELAY_SIGNAL(_eventHandler, SIGNAL(newDescriptors(QStringList)));
RELAY_SIGNAL(_eventHandler, SIGNAL(newConsensus()));
RELAY_SIGNAL(_eventHandler, SIGNAL(logMessage(tc::Severity, QString)));
diff --git a/src/torcontrol/TorControl.h b/src/torcontrol/TorControl.h
index ec91679..3aa78d3 100644
--- a/src/torcontrol/TorControl.h
+++ b/src/torcontrol/TorControl.h
@@ -277,6 +277,14 @@ signals:
*/
void circuitStatusChanged(const Circuit &circuit);
+ /** Emitted when Tor sends a bandwidth usage update for a stream.
+ * <b>bytesReceived</b> is the number of bytes read on the stream over
+ * the previous second and <b>bytesWritten</b> is the number of bytes
+ * sent over the same interval.
+ */
+ void streamBandwidthUpdate(const StreamId &streamId,
+ quint64 bytesReceived, quint64 bytesSent);
+
/** Emitted when Tor has mapped the address <b>from</b> to the address
* <b>to</b>. <b>expires</b> indicates the time at which when the address
* mapping will no longer be considered valid.
diff --git a/src/torcontrol/TorEvents.cpp b/src/torcontrol/TorEvents.cpp
index db337e5..8b7c401 100644
--- a/src/torcontrol/TorEvents.cpp
+++ b/src/torcontrol/TorEvents.cpp
@@ -41,6 +41,7 @@ TorEvents::TorEvents(QObject *parent)
qRegisterMetaType<BootstrapStatus>("BootstrapStatus");
qRegisterMetaType<Circuit>("Circuit");
qRegisterMetaType<Stream>("Stream");
+ qRegisterMetaType<StreamId>("StreamId");
qRegisterMetaType<QHostAddress>("QHostAddress");
qRegisterMetaType<QDateTime>("QDateTime");
@@ -66,6 +67,7 @@ TorEvents::toString(Event e)
case ClientStatus: event = "STATUS_CLIENT"; break;
case ServerStatus: event = "STATUS_SERVER"; break;
case NewConsensus: event = "NEWCONSENSUS"; break;
+ case StreamBandwidth: event = "STREAM_BW"; break;
default: event = "UNKNOWN"; break;
}
return event;
@@ -104,6 +106,8 @@ TorEvents::toTorEvent(const QString &event)
e = ServerStatus;
} else if (event == "NEWCONSENSUS") {
e = NewConsensus;
+ } else if (event == "STREAM_BW") {
+ e = StreamBandwidth;
} else {
e = Unknown;
}
@@ -131,6 +135,7 @@ TorEvents::handleEvent(const ControlReply &reply)
case Bandwidth: handleBandwidthUpdate(line); break;
case CircuitStatus: handleCircuitStatus(line); break;
case StreamStatus: handleStreamStatus(line); break;
+ case StreamBandwidth:handleStreamBandwidthUpdate(line); break;
case NewDescriptor: handleNewDescriptor(line); break;
case NewConsensus: handleNewConsensus(line); break;
case AddressMap: handleAddressMap(line); break;
@@ -225,6 +230,27 @@ TorEvents::handleStreamStatus(const ReplyLine &line)
}
}
+/** Handle a stream bandwidth update event. The format of this message is:
+ *
+ * "650" SP "STREAM_BW" SP StreamID SP BytesWritten SP BytesRead
+ * BytesWritten = 1*DIGIT
+ * BytesRead = 1*DIGIT
+ */
+void
+TorEvents::handleStreamBandwidthUpdate(const ReplyLine &line)
+{
+ QStringList msg = line.getMessage().split(" ");
+ if (msg.size() >= 4) {
+ StreamId streamId = msg.at(1);
+ quint64 bytesSent = (quint64)msg.at(2).toULongLong();
+ quint64 bytesReceived = (quint64)msg.at(3).toULongLong();
+
+ /* Post the event to each of the interested targets */
+ if (Stream::isValidStreamId(streamId))
+ emit streamBandwidthUpdate(streamId, bytesReceived, bytesSent);
+ }
+}
+
/** Handle a log message event. The format of this message is:
* The syntax is:
*
diff --git a/src/torcontrol/TorEvents.h b/src/torcontrol/TorEvents.h
index 832034d..4642a7e 100644
--- a/src/torcontrol/TorEvents.h
+++ b/src/torcontrol/TorEvents.h
@@ -25,6 +25,7 @@
class Circuit;
class Stream;
+typedef QString StreamId;
class BootstrapStatus;
class ControlReply;
class ReplyLine;
@@ -41,25 +42,26 @@ class TorEvents : public QObject
public:
/** Asynchronous events sent from Tor to the controller */
enum Event {
- Unknown = 0,
- Bandwidth = (1u << 0),
- LogDebug = (1u << 1),
- LogInfo = (1u << 2),
- LogNotice = (1u << 3),
- LogWarn = (1u << 4),
- LogError = (1u << 5),
- CircuitStatus = (1u << 6),
- StreamStatus = (1u << 7),
- OrConnStatus = (1u << 8),
- NewDescriptor = (1u << 9),
- AddressMap = (1u << 10),
- GeneralStatus = (1u << 11),
- ClientStatus = (1u << 12),
- ServerStatus = (1u << 13),
- NewConsensus = (1u << 14),
+ Unknown = 0,
+ Bandwidth = (1u << 0),
+ LogDebug = (1u << 1),
+ LogInfo = (1u << 2),
+ LogNotice = (1u << 3),
+ LogWarn = (1u << 4),
+ LogError = (1u << 5),
+ CircuitStatus = (1u << 6),
+ StreamStatus = (1u << 7),
+ OrConnStatus = (1u << 8),
+ NewDescriptor = (1u << 9),
+ AddressMap = (1u << 10),
+ GeneralStatus = (1u << 11),
+ ClientStatus = (1u << 12),
+ ServerStatus = (1u << 13),
+ NewConsensus = (1u << 14),
+ StreamBandwidth = (1u << 15),
};
static const Event EVENT_MIN = TorEvents::Bandwidth;
- static const Event EVENT_MAX = TorEvents::NewConsensus;
+ static const Event EVENT_MAX = TorEvents::StreamBandwidth;
Q_DECLARE_FLAGS(Events, Event);
/** Default Constructor */
@@ -92,6 +94,14 @@ signals:
*/
void circuitStatusChanged(const Circuit &circuit);
+ /** Emitted when Tor sends a bandwidth usage update for a stream.
+ * <b>bytesReceived</b> is the number of bytes read on the stream over
+ * the previous second and <b>bytesWritten</b> is the number of bytes
+ * sent over the same interval.
+ */
+ void streamBandwidthUpdate(const StreamId &streamId,
+ quint64 bytesReceived, quint64 bytesSent);
+
/** Emitted when Tor has mapped the address <b>from</b> to the address
* <b>to</b>. <b>expires</b> indicates the time at which when the address
* mapping will no longer be considered valid.
@@ -227,6 +237,8 @@ private:
void handleCircuitStatus(const ReplyLine &line);
/** Handle a stream status event */
void handleStreamStatus(const ReplyLine &line);
+ /** Handle a stream bandwidth event */
+ void handleStreamBandwidthUpdate(const ReplyLine &line);
/** Handle a log message event */
void handleLogMessage(const ReplyLine &line);
/** Handle an OR connection status event. */
diff --git a/src/vidalia/network/CircuitListWidget.cpp b/src/vidalia/network/CircuitListWidget.cpp
index 4773d9b..a92ad9c 100644
--- a/src/vidalia/network/CircuitListWidget.cpp
+++ b/src/vidalia/network/CircuitListWidget.cpp
@@ -34,7 +34,7 @@ CircuitListWidget::CircuitListWidget(QWidget *parent)
: QTreeWidget(parent)
{
/* Create and initialize columns */
- setHeaderLabels(QStringList() << tr("Connection") << tr("Status"));
+ setHeaderLabels(QStringList() << tr("Connection") << tr("Status") << tr("Traffic"));
/* Find out when a circuit has been selected */
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
@@ -52,13 +52,14 @@ CircuitListWidget::CircuitListWidget(QWidget *parent)
void
CircuitListWidget::retranslateUi()
{
- setHeaderLabels(QStringList() << tr("Connection") << tr("Status"));
+ setHeaderLabels(QStringList() << tr("Connection") << tr("Status") << tr("Traffic"));
for (int i = 0; i < topLevelItemCount(); i++) {
CircuitItem *circuitItem = dynamic_cast<CircuitItem *>(topLevelItem(i));
circuitItem->update(circuitItem->circuit());
foreach (StreamItem *streamItem, circuitItem->streams()) {
streamItem->update(streamItem->stream());
+ streamItem->setTraffic(streamItem->bytesReceived(), streamItem->bytesSent());
}
}
}
@@ -197,6 +198,20 @@ CircuitListWidget::addStream(const Stream &stream)
}
}
+/** Updates the traffic totals for a stream with the given delta values. */
+void
+CircuitListWidget::onStreamBandwidthUpdate(const StreamId &streamId,
+ quint64 bytesReceived,
+ quint64 bytesSent)
+{
+ StreamItem *item = findStreamItem(streamId);
+ if (item) {
+ item->setTraffic(
+ item->bytesReceived() + bytesReceived,
+ item->bytesSent() + bytesSent);
+ }
+}
+
/** Schedules the given circuit to be removed after the specified timeout. */
void
CircuitListWidget::scheduleCircuitRemoval(CircuitItem *circuit, int delay)
diff --git a/src/vidalia/network/CircuitListWidget.h b/src/vidalia/network/CircuitListWidget.h
index 1405b17..7fb4d5e 100644
--- a/src/vidalia/network/CircuitListWidget.h
+++ b/src/vidalia/network/CircuitListWidget.h
@@ -34,7 +34,8 @@ public:
/** Circuit list columns. */
enum Columns {
ConnectionColumn = 0, /**< Column for either the circuit or stream */
- StatusColumn = 1 /**< Status of the connection. */
+ StatusColumn = 1, /**< Status of the connection. */
+ TrafficColumn = 2, /**< Amount of data received and sent by the stream. */
};
/** Default constructor */
@@ -66,6 +67,9 @@ signals:
public slots:
/** Clears all circuits and streams from the list. */
void clearCircuits();
+ /** Updates the traffic totals for a stream with the given delta values. */
+ void onStreamBandwidthUpdate(const StreamId &streamId,
+ quint64 bytesReceived, quint64 bytesSent);
private slots:
/** Removes the first circuit scheduled to be removed.*/
diff --git a/src/vidalia/network/NetViewer.cpp b/src/vidalia/network/NetViewer.cpp
index 2747cd6..475a35e 100644
--- a/src/vidalia/network/NetViewer.cpp
+++ b/src/vidalia/network/NetViewer.cpp
@@ -103,6 +103,10 @@ NetViewer::NetViewer(QWidget *parent)
connect(_torControl, SIGNAL(streamStatusChanged(Stream)),
this, SLOT(addStream(Stream)));
+ _torControl->setEvent(TorEvents::StreamBandwidth);
+ connect(_torControl, SIGNAL(streamBandwidthUpdate(StreamId, quint64, quint64)),
+ ui.treeCircuitList, SLOT(onStreamBandwidthUpdate(StreamId, quint64, quint64)));
+
_torControl->setEvent(TorEvents::AddressMap);
connect(_torControl, SIGNAL(addressMapped(QString, QString, QDateTime)),
this, SLOT(addressMapped(QString, QString, QDateTime)));
diff --git a/src/vidalia/network/NetViewer.ui b/src/vidalia/network/NetViewer.ui
index 7994fb9..9d8dc87 100644
--- a/src/vidalia/network/NetViewer.ui
+++ b/src/vidalia/network/NetViewer.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>740</width>
- <height>786</height>
+ <height>752</height>
</rect>
</property>
<property name="windowTitle">
@@ -224,7 +224,7 @@
<bool>false</bool>
</property>
<property name="columnCount">
- <number>2</number>
+ <number>3</number>
</property>
<column>
<property name="text">
@@ -236,6 +236,11 @@
<string>Status</string>
</property>
</column>
+ <column>
+ <property name="text">
+ <string>Traffic</string>
+ </property>
+ </column>
</widget>
</item>
</layout>
@@ -279,7 +284,7 @@
<bool>false</bool>
</property>
<property name="columnCount">
- <number>2</number>
+ <number>3</number>
</property>
<column>
<property name="text">
@@ -291,6 +296,11 @@
<string>Status</string>
</property>
</column>
+ <column>
+ <property name="text">
+ <string>Traffic</string>
+ </property>
+ </column>
</widget>
</item>
</layout>
@@ -334,7 +344,7 @@
<bool>false</bool>
</property>
<property name="columnCount">
- <number>2</number>
+ <number>3</number>
</property>
<column>
<property name="text">
@@ -346,6 +356,11 @@
<string>Status</string>
</property>
</column>
+ <column>
+ <property name="text">
+ <string>Traffic</string>
+ </property>
+ </column>
</widget>
</item>
</layout>
diff --git a/src/vidalia/network/StreamItem.cpp b/src/vidalia/network/StreamItem.cpp
index 5083b81..6d77afe 100644
--- a/src/vidalia/network/StreamItem.cpp
+++ b/src/vidalia/network/StreamItem.cpp
@@ -19,6 +19,7 @@
/** Constructor */
StreamItem::StreamItem(const Stream &stream)
+ : _bytesReceived(0), _bytesSent(0)
{
/* Set the stream's displayed target information */
setText(CircuitListWidget::ConnectionColumn, stream.target());
@@ -37,3 +38,36 @@ StreamItem::update(const Stream &stream)
setToolTip(CircuitListWidget::StatusColumn, stream.statusString());
}
+/** Formats a count of bytes appropriately as bytes, kilobytes,
+ * megabytes, or gigabytes. */
+static
+QString formatBytes(quint64 bytes) {
+ const int K = 1024, M = K * K, G = K * M;
+ double d = bytes;
+ /*if (bytes < 1 * K) return QString("%1 B").arg(bytes);*/
+ if (bytes < 10 * K) return QString("%1 KB").arg(d / K, 0, 'f', 1);
+ if (bytes < 1 * M) return QString("%1 KB").arg(d / K, 0, 'f', 0);
+ if (bytes < 100 * M) return QString("%1 MB").arg(d / M, 0, 'f', 1);
+ if (bytes < 1 * G) return QString("%1 MB").arg(d / M, 0, 'f', 0);
+ return QString("%1 GB").arg(d / G, 0, 'f', 1);
+}
+
+/** Updates the traffic totals of this stream item. */
+void
+StreamItem::setTraffic(quint64 bytesReceived, quint64 bytesSent)
+{
+ _bytesReceived = bytesReceived;
+ _bytesSent = bytesSent;
+
+ QString str;
+ if (bytesReceived | bytesSent) {
+ str = QString("%1 down / %2 up").arg(
+ formatBytes(bytesReceived),
+ formatBytes(bytesSent));
+ } else {
+ str = QString();
+ }
+
+ setText(CircuitListWidget::TrafficColumn, str);
+ setToolTip(CircuitListWidget::TrafficColumn, str);
+}
diff --git a/src/vidalia/network/StreamItem.h b/src/vidalia/network/StreamItem.h
index ea8d906..1521d03 100644
--- a/src/vidalia/network/StreamItem.h
+++ b/src/vidalia/network/StreamItem.h
@@ -33,8 +33,15 @@ public:
/** Returns the ID of the stream associated with this tree item. */
StreamId id() const { return _stream.id(); }
+ /** Updates the traffic totals of this stream item. */
+ void setTraffic(quint64 bytesReceived, quint64 bytesSent);
+ quint64 bytesReceived() const { return _bytesReceived; }
+ quint64 bytesSent() const { return _bytesSent; }
+
private:
Stream _stream;
+ quint64 _bytesReceived;
+ quint64 _bytesSent;
};
#endif