commit ece9744a678d5601fcf76a2cbb668a88422c75eb Author: Tomás Touceda chiiph@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
tor-commits@lists.torproject.org