/**************************************************************** * RetroShare is distributed under the following license: * * Copyright (C) 2011 Robert Fernie * * 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 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. ****************************************************************/ #include "DhtWindow.h" #include "ui_DhtWindow.h" #include "util/QtVersion.h" #include #include #include #include #include #include #include #include #include "retroshare-gui/RsAutoUpdatePage.h" #include "retroshare/rsdht.h" #include "retroshare/rsconfig.h" #include "retroshare/rspeers.h" #define DTW_COL_BUCKET 0 #define DTW_COL_IPADDR 1 #define DTW_COL_PEERID 2 #define DTW_COL_FLAGS 3 #define DTW_COL_FOUND 4 #define DTW_COL_SEND 5 #define DTW_COL_RECV 6 DhtWindow::DhtWindow(QWidget *parent) : RsAutoUpdatePage(1000,parent) { ui.setupUi(this); connect( ui.filterLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(filterItems(QString))); connect( ui.filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterColumnChanged(int))); connect( ui.dhtTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(DHTCustomPopupMenu(QPoint))); /* add filter actions */ ui.filterLineEdit->addFilter(QIcon(), tr("IP"), DTW_COL_IPADDR, tr("Search IP")); ui.filterLineEdit->setCurrentFilter(DTW_COL_IPADDR); } DhtWindow::~DhtWindow() { } void DhtWindow::DHTCustomPopupMenu( QPoint ) { QMenu contextMnu( this ); QTreeWidgetItem *item = ui.dhtTreeWidget->currentItem(); if (item) { QString Ip = item->text(DTW_COL_IPADDR); contextMnu.addAction(QIcon(), tr("Copy %1 to clipboard").arg(Ip), this, SLOT(copyIP())); } contextMnu.exec(QCursor::pos()); } void DhtWindow::updateDisplay() { /* do nothing if locked, or not visible */ if (RsAutoUpdatePage::eventsLocked() == true) { #ifdef DEBUG_DHTWINDOW std::cerr << "DhtWindow::update() events Are Locked" << std::endl; #endif return; } if (!rsDht) { #ifdef DEBUG_DHTWINDOW std::cerr << "DhtWindow::update rsDht NOT Set" << std::endl; #endif return; } RsAutoUpdatePage::lockAllEvents(); //std::cerr << "DhtWindow::update()" << std::endl; updateNetStatus(); updateNetPeers(); updateDhtPeers(); updateRelays(); RsAutoUpdatePage::unlockAllEvents() ; QHeaderView_setSectionResizeMode(ui.peerTreeWidget->header(), QHeaderView::ResizeToContents); QHeaderView_setSectionResizeMode(ui.dhtTreeWidget->header(), QHeaderView::ResizeToContents); QHeaderView_setSectionResizeMode(ui.relayTreeWidget->header(), QHeaderView::ResizeToContents); } void DhtWindow::updateNetStatus() { QString status; QString oldstatus; #if 0 status = QString::fromStdString(mPeerNet->getPeerStatusString()); oldstatus = ui.peerLine->text(); if (oldstatus != status) { ui.peerLine->setText(status); } #endif status = QString::fromStdString(rsDht->getUdpAddressString()); oldstatus = ui.peerAddressLabel->text(); if (oldstatus != status) { ui.peerAddressLabel->setText(status); } uint32_t netMode = rsConfig->getNetworkMode(); QLabel *label = ui.networkLabel; switch(netMode) { case RSNET_NETWORK_UNKNOWN: label->setText(tr("Unknown NetState")); break; case RSNET_NETWORK_OFFLINE: label->setText(tr("Offline")); break; case RSNET_NETWORK_LOCALNET: label->setText(tr("Local Net")); break; case RSNET_NETWORK_BEHINDNAT: label->setText(tr("Behind NAT")); break; case RSNET_NETWORK_EXTERNALIP: label->setText(tr("External IP")); break; } label = ui.natTypeLabel; uint32_t natType = rsConfig->getNatTypeMode(); switch(natType) { case RSNET_NATTYPE_UNKNOWN: label->setText(tr("UNKNOWN NAT STATE")); break; case RSNET_NATTYPE_SYMMETRIC: label->setText(tr("SYMMETRIC NAT")); break; case RSNET_NATTYPE_DETERM_SYM: label->setText(tr("DETERMINISTIC SYM NAT")); break; case RSNET_NATTYPE_RESTRICTED_CONE: label->setText(tr("RESTRICTED CONE NAT")); break; case RSNET_NATTYPE_FULL_CONE: label->setText(tr("FULL CONE NAT")); break; case RSNET_NATTYPE_OTHER: label->setText(tr("OTHER NAT")); break; case RSNET_NATTYPE_NONE: label->setText(tr("NO NAT")); break; } label = ui.natHoleLabel; uint32_t natHole = rsConfig->getNatHoleMode(); switch(natHole) { case RSNET_NATHOLE_UNKNOWN: label->setText(tr("UNKNOWN NAT HOLE STATUS")); break; case RSNET_NATHOLE_NONE: label->setText(tr("NO NAT HOLE")); break; case RSNET_NATHOLE_UPNP: label->setText(tr("UPNP FORWARD")); break; case RSNET_NATHOLE_NATPMP: label->setText(tr("NATPMP FORWARD")); break; case RSNET_NATHOLE_FORWARDED: label->setText(tr("MANUAL FORWARD")); break; } uint32_t connect = rsConfig->getConnectModes(); label = ui.connectLabel; QString connOut; if (connect & RSNET_CONNECT_OUTGOING_TCP) { connOut += "TCP_OUT "; } if (connect & RSNET_CONNECT_ACCEPT_TCP) { connOut += "TCP_IN "; } if (connect & RSNET_CONNECT_DIRECT_UDP) { connOut += "DIRECT_UDP "; } if (connect & RSNET_CONNECT_PROXY_UDP) { connOut += "PROXY_UDP "; } if (connect & RSNET_CONNECT_RELAY_UDP) { connOut += "RELAY_UDP "; } label->setText(connOut); uint32_t netState = rsConfig->getNetState(); label = ui.netStatusLabel; switch(netState) { case RSNET_NETSTATE_BAD_UNKNOWN: label->setText(tr("NET BAD: Unknown State")); break; case RSNET_NETSTATE_BAD_OFFLINE: label->setText(tr("NET BAD: Offline")); break; case RSNET_NETSTATE_BAD_NATSYM: label->setText(tr("NET BAD: Behind Symmetric NAT")); break; case RSNET_NETSTATE_BAD_NODHT_NAT: label->setText(tr("NET BAD: Behind NAT & No DHT")); break; case RSNET_NETSTATE_WARNING_RESTART: label->setText(tr("NET WARNING: NET Restart")); break; case RSNET_NETSTATE_WARNING_NATTED: label->setText(tr("NET WARNING: Behind NAT")); break; case RSNET_NETSTATE_WARNING_NODHT: label->setText(tr("NET WARNING: No DHT")); break; case RSNET_NETSTATE_GOOD: label->setText(tr("NET STATE GOOD!")); break; case RSNET_NETSTATE_ADV_FORWARD: label->setText(tr("CAUTION: UNVERIFIABLE FORWARD!")); break; case RSNET_NETSTATE_ADV_DARK_FORWARD: label->setText(tr("CAUTION: UNVERIFIABLE FORWARD & NO DHT")); break; } } void DhtWindow::updateNetPeers() { //QTreeWidget *peerTreeWidget = ui.peerTreeWidget; std::list peerIds; std::list::iterator it; rsDht->getNetPeerList(peerIds); /* collate peer stats */ int nPeers = peerIds.size(); // from DHT peers int nOnlinePeers = 0; int nUnreachablePeers = 0; int nOfflinePeers = 0; // Connect States. int nDisconnPeers = 0; int nDirectPeers = 0; int nProxyPeers = 0; int nRelayPeers = 0; #define PTW_COL_RSNAME 0 #define PTW_COL_PEERID 1 #define PTW_COL_DHT_STATUS 2 #define PTW_COL_PEER_CONNECTLOGIC 3 #define PTW_COL_PEER_CONNECT_STATUS 4 #define PTW_COL_PEER_CONNECT_MODE 5 #define PTW_COL_PEER_REQ_STATUS 6 #define PTW_COL_PEER_CB_MSG 7 #define PTW_COL_RSID 8 #if 0 /* clear old entries */ int itemCount = peerTreeWidget->topLevelItemCount(); for (int nIndex = 0; nIndex < itemCount;) { QTreeWidgetItem *tmp_item = ui.peerTreeWidget->topLevelItem(nIndex); std::string tmpid = tmp_item->data(PTW_COL_PEERID, Qt::DisplayRole).toString().toStdString(); if (peerIds.end() == std::find(peerIds.begin(), peerIds.end(), tmpid)) { ui.peerTreeWidget->removeItemWidget(tmp_item, 0); /* remove it! */ itemCount--; } else { ++nIndex; } } #endif ui.peerTreeWidget->clear(); for(it = peerIds.begin(); it != peerIds.end(); ++it) { /* find the entry */ QTreeWidgetItem *peer_item = NULL; #if 0 QString qpeerid = QString::fromStdString(*it); int itemCount = ui.peerTreeWidget->topLevelItemCount(); for (int nIndex = 0; nIndex < itemCount; ++nIndex) { QTreeWidgetItem *tmp_item = ui.peerTreeWidget->topLevelItem(nIndex); if (tmp_item->data(PTW_COL_PEERID, Qt::DisplayRole).toString() == qpeerid) { peer_item = tmp_item; break; } } #endif if (!peer_item) { /* insert */ peer_item = new QTreeWidgetItem(); ui.peerTreeWidget->addTopLevelItem(peer_item); } /* Set header resize modes and initial section sizes Peer TreeView*/ QHeaderView * _header = ui.peerTreeWidget->header () ; _header->resizeSection ( PTW_COL_RSNAME, 170 ); /* update the data */ RsDhtNetPeer status; rsDht->getNetPeerStatus(*it, status); std::string name = rsPeers->getPeerName(*it); peer_item -> setData(PTW_COL_PEERID, Qt::DisplayRole, QString::fromStdString(status.mDhtId)); peer_item -> setData(PTW_COL_RSNAME, Qt::DisplayRole, QString::fromUtf8(name.c_str())); peer_item -> setData(PTW_COL_RSID, Qt::DisplayRole, QString::fromStdString(status.mRsId.toStdString())); QString dhtstate; switch(status.mDhtState) { default: case RSDHT_PEERDHT_NOT_ACTIVE: dhtstate = tr("Not Active (Maybe Connected!)"); break; case RSDHT_PEERDHT_SEARCHING: dhtstate = tr("Searching"); break; case RSDHT_PEERDHT_FAILURE: dhtstate = tr("Failed"); break; case RSDHT_PEERDHT_OFFLINE: dhtstate = tr("offline"); ++nOfflinePeers; break; case RSDHT_PEERDHT_UNREACHABLE: dhtstate = tr("Unreachable"); ++nUnreachablePeers; break; case RSDHT_PEERDHT_ONLINE: dhtstate = tr("ONLINE"); ++nOnlinePeers; break; } peer_item -> setData(PTW_COL_DHT_STATUS, Qt::DisplayRole, dhtstate); // NOW CONNECT STATE QString cpmstr; switch(status.mPeerConnectMode) { case RSDHT_TOU_MODE_DIRECT: cpmstr = tr("Direct"); break; case RSDHT_TOU_MODE_PROXY: cpmstr = tr("Proxy VIA")+" " + QString::fromStdString(status.mPeerConnectProxyId); break; case RSDHT_TOU_MODE_RELAY: cpmstr = tr("Relay VIA")+" " + QString::fromStdString(status.mPeerConnectProxyId); break; default: case RSDHT_TOU_MODE_NONE: cpmstr = tr("None"); break; } QString cpsstr; switch(status.mPeerConnectState) { default: case RSDHT_PEERCONN_DISCONNECTED: cpsstr = tr("Disconnected"); ++nDisconnPeers; break; case RSDHT_PEERCONN_UDP_STARTED: cpsstr = tr("Udp Started"); break; case RSDHT_PEERCONN_CONNECTED: { cpsstr = tr("Connected"); break; switch(status.mPeerConnectMode) { default: case RSDHT_TOU_MODE_DIRECT: ++nDirectPeers; break; case RSDHT_TOU_MODE_PROXY: ++nProxyPeers; break; case RSDHT_TOU_MODE_RELAY: ++nRelayPeers; break; } } break; } peer_item -> setData(PTW_COL_PEER_CONNECT_STATUS, Qt::DisplayRole, cpsstr); if (status.mPeerConnectState == RSDHT_PEERCONN_DISCONNECTED) { peer_item -> setData(PTW_COL_PEER_CONNECT_MODE, Qt::DisplayRole, ""); } else { peer_item -> setData(PTW_COL_PEER_CONNECT_MODE, Qt::DisplayRole, cpmstr); } // NOW REQ STATE. QString reqstr; if (status.mExclusiveProxyLock) { reqstr = "(E) "; } switch(status.mPeerReqState) { case RSDHT_PEERREQ_RUNNING: reqstr += tr("Request Active"); break; case RSDHT_PEERREQ_STOPPED: reqstr += tr("No Request"); break; default: reqstr += tr("Unknown"); break; } peer_item -> setData(PTW_COL_PEER_REQ_STATUS, Qt::DisplayRole, reqstr); peer_item -> setData(PTW_COL_PEER_CB_MSG, Qt::DisplayRole, QString::fromStdString(status.mCbPeerMsg)); peer_item -> setData(PTW_COL_PEER_CONNECTLOGIC, Qt::DisplayRole, QString::fromStdString(status.mConnectState)); } /*QString connstr; connstr = tr("#Peers: ") + QString::number(nPeers); connstr += tr(" DHT: (#off:") + QString::number(nOfflinePeers); connstr += tr(",unreach:") + QString::number(nUnreachablePeers); connstr += tr(",online:") + QString::number(nOnlinePeers); connstr += tr(") Connections: (#dis:") + QString::number(nDisconnPeers); connstr += tr(",#dir:") + QString::number(nDirectPeers); connstr += tr(",#proxy:") + QString::number(nProxyPeers); connstr += tr(",#relay:") + QString::number(nRelayPeers); connstr += ")";*/ ui.label_peers->setText(QString::number(nPeers)); ui.label_offline->setText(QString::number(nOfflinePeers)); ui.label_unreachable->setText(QString::number(nUnreachablePeers)); ui.label_online->setText(QString::number(nOnlinePeers)); ui.label_disconnected->setText(QString::number(nDisconnPeers)); ui.label_direct->setText(QString::number(nDirectPeers)); ui.label_proxy->setText(QString::number(nProxyPeers)); ui.label_relay->setText(QString::number(nRelayPeers)); ui.tabWidget_2->setTabText(1, tr("Peers") + " (" + QString::number(ui.peerTreeWidget->topLevelItemCount()) + ")" ); //peerSummaryLabel->setText(connstr); } void DhtWindow::updateRelays() { QTreeWidget *relayTreeWidget = ui.relayTreeWidget; std::list relayEnds; std::list relayProxies; std::list::iterator reit; std::list::iterator rpit; rsDht->getRelayEnds(relayEnds); rsDht->getRelayProxies(relayProxies); #define RTW_COL_TYPE 0 #define RTW_COL_SRC 1 #define RTW_COL_PROXY 2 #define RTW_COL_DEST 3 #define RTW_COL_CLASS 4 #define RTW_COL_AGE 5 #define RTW_COL_LASTSEND 6 #define RTW_COL_BANDWIDTH 7 relayTreeWidget->clear(); time_t now = time(NULL); for(reit = relayEnds.begin(); reit != relayEnds.end(); ++reit) { /* find the entry */ QTreeWidgetItem *item = new QTreeWidgetItem(); ui.relayTreeWidget->addTopLevelItem(item); QString typestr = tr("RELAY END"); QString srcstr = tr("Yourself"); QString proxystr = QString::fromStdString(reit->mProxyAddr); QString deststr = QString::fromStdString(reit->mRemoteAddr); QString agestr = tr("unknown"); QString lastsendstr = tr("unknown"); QString bandwidthstr = tr("unlimited"); QString classstr = tr("Own Relay"); //std::ostringstream dhtupdatestr; //dhtupdatestr << now - status.mDhtUpdateTS << " secs ago"; item -> setData(RTW_COL_TYPE, Qt::DisplayRole, typestr); item -> setData(RTW_COL_SRC, Qt::DisplayRole, srcstr); item -> setData(RTW_COL_PROXY, Qt::DisplayRole, proxystr); item -> setData(RTW_COL_DEST, Qt::DisplayRole, deststr); item -> setData(RTW_COL_CLASS, Qt::DisplayRole, classstr); item -> setData(RTW_COL_AGE, Qt::DisplayRole, agestr); item -> setData(RTW_COL_LASTSEND, Qt::DisplayRole, lastsendstr); item -> setData(RTW_COL_BANDWIDTH, Qt::DisplayRole, bandwidthstr); } for(rpit = relayProxies.begin(); rpit != relayProxies.end(); ++rpit) { /* find the entry */ QTreeWidgetItem *item = new QTreeWidgetItem(); ui.relayTreeWidget->addTopLevelItem(item); QString typestr = tr("RELAY PROXY"); QString srcstr = QString::fromStdString(rpit->mSrcAddr); QString proxystr = tr("Yourself"); QString deststr = QString::fromStdString(rpit->mDestAddr); QString agestr = QString(tr("%1 secs ago")).arg(now - rpit->mCreateTS); QString lastsendstr = QString(tr("%1 secs ago")).arg(now - rpit->mLastTS); QString bandwidthstr = QString(tr("%1B/s")).arg(QString::number(rpit->mBandwidth)); QString classstr = QString::number(rpit->mRelayClass); item -> setData(RTW_COL_TYPE, Qt::DisplayRole, typestr); item -> setData(RTW_COL_SRC, Qt::DisplayRole, srcstr); item -> setData(RTW_COL_PROXY, Qt::DisplayRole, proxystr); item -> setData(RTW_COL_DEST, Qt::DisplayRole, deststr); item -> setData(RTW_COL_CLASS, Qt::DisplayRole, classstr); item -> setData(RTW_COL_AGE, Qt::DisplayRole, agestr); item -> setData(RTW_COL_LASTSEND, Qt::DisplayRole, lastsendstr); item -> setData(RTW_COL_BANDWIDTH, Qt::DisplayRole, bandwidthstr); } ui.tabWidget_2->setTabText(2, tr("Relays") + " (" + QString::number(ui.relayTreeWidget->topLevelItemCount()) + ")" ); } /****************************/ class DhtTreeWidgetItem : public QTreeWidgetItem { public: virtual bool operator<(const QTreeWidgetItem &other) const { int column = treeWidget()->sortColumn(); if (column == DTW_COL_RECV || column == DTW_COL_SEND || column == DTW_COL_BUCKET) { QString t1 = text(column); QString t2 = other.text(column); t1 = t1.left(t1.indexOf(' ')); t2 = t2.left(t2.indexOf(' ')); return t1.toLong() < t2.toLong(); } return text(column) < other.text(column); } }; void DhtWindow::updateDhtPeers() { /* Hackish display of all Dht peers, should be split into buckets (as children) */ //QString status = QString::fromStdString(mPeerNet->getDhtStatusString()); //dhtLabel->setText(status); std::list allpeers; std::list::iterator it; int i; for(i = 0; i < 160; ++i) { std::list peers; rsDht->getDhtPeers(i, peers); for(it = peers.begin(); it != peers.end(); ++it) { allpeers.push_back(*it); } } //QTreeWidget *dhtTreeWidget = ui.dhtTreeWidget; ui.dhtTreeWidget->clear(); time_t now = time(NULL); for(it = allpeers.begin(); it != allpeers.end(); ++it) { /* find the entry */ QTreeWidgetItem *dht_item = NULL; /* insert */ dht_item = new DhtTreeWidgetItem(); QString buckstr = QString::number(it->mBucket); QString ipstr = QString::fromStdString(it->mAddr); QString idstr = QString::fromStdString(it->mDhtId); QString flagsstr = QString(tr("0x%1 EX:0x%2")).arg(it->mPeerFlags, 0, 16, QChar('0')).arg(it->mExtraFlags, 0, 16, QChar('0')); QString foundstr = QString(tr("%1 secs ago")).arg(now - it->mFoundTime); QString lastsendstr; if (it->mLastSendTime == 0) { lastsendstr = tr("never"); } else { lastsendstr = QString (tr("%1 secs ago")).arg(now - it->mLastSendTime); } QString lastrecvstr = QString (tr("%1 secs ago")).arg(now - it->mLastRecvTime); dht_item -> setData(DTW_COL_BUCKET, Qt::DisplayRole, buckstr); dht_item -> setData(DTW_COL_IPADDR, Qt::DisplayRole, ipstr); dht_item -> setData(DTW_COL_PEERID, Qt::DisplayRole, idstr); dht_item -> setData(DTW_COL_FLAGS, Qt::DisplayRole, flagsstr); dht_item -> setData(DTW_COL_FOUND, Qt::DisplayRole, foundstr); dht_item -> setData(DTW_COL_SEND, Qt::DisplayRole, lastsendstr); dht_item -> setData(DTW_COL_RECV, Qt::DisplayRole, lastrecvstr); ui.dhtTreeWidget->addTopLevelItem(dht_item); if (ui.filterLineEdit->text().isEmpty() == false) { filterItems(ui.filterLineEdit->text()); } ui.tabWidget_2->setTabText(0, tr("DHT") + " (" + QString::number(ui.dhtTreeWidget->topLevelItemCount()) + ")" ); } } void DhtWindow::getDHTStatus() { // RsConfigNetStatus config; // rsConfig->getConfigNetStatus(config); // // if (!(config.DHTActive)) // { // // GRAY. // } // else // { // if (config.netDhtOk) // { // #define MIN_RS_NET_SIZE 10 // // YELLOW or GREEN. // if (config.netDhtRsNetSize < MIN_RS_NET_SIZE) // { // updateGraph(config.netDhtRsNetSize,config.netDhtNetSize); // } // else // { // updateGraph(config.netDhtRsNetSize,config.netDhtNetSize); // } // } // else // { // // RED - some issue. // // } // } } void DhtWindow::filterColumnChanged(int) { filterItems(ui.filterLineEdit->text()); } void DhtWindow::filterItems(const QString &text) { int filterColumn = ui.filterLineEdit->currentFilter(); int count = ui.dhtTreeWidget->topLevelItemCount (); for (int index = 0; index < count; ++index) { filterItem(ui.dhtTreeWidget->topLevelItem(index), text, filterColumn); } } bool DhtWindow::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn) { bool visible = true; if (text.isEmpty() == false) { if (item->text(filterColumn).contains(text, Qt::CaseInsensitive) == false) { visible = false; } } int visibleChildCount = 0; int count = item->childCount(); for (int index = 0; index < count; ++index) { if (filterItem(item->child(index), text, filterColumn)) { ++visibleChildCount; } } if (visible || visibleChildCount) { item->setHidden(false); } else { item->setHidden(true); } return (visible || visibleChildCount); } void DhtWindow::copyIP() { QTreeWidgetItem *item = ui.dhtTreeWidget->currentItem(); if (!item) { return; } QString Ip = item->text(DTW_COL_IPADDR); QApplication::clipboard()->setText(Ip, QClipboard::Clipboard); }