00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "Qt.h"
00024 #include "ConnectionKeeper.h"
00025 #include "NodeCache.h"
00026 #include "NodeCacheFilters.h"
00027 #include "UdpHostCache.h"
00028 #include "Imports.cpp"
00029
00030 using namespace Gnutella::Bootstrapping;
00031
00032 namespace Gnutella {
00033 namespace Bootstrapping {
00034
00035 enum Constants
00036 {
00037 UdpPingTimeout = 2000,
00038 UdpPingTries = 5,
00039 UdpPingsPerTry = 10
00040 };
00041
00042 static const float HighUptimeThreshold = 0.7;
00043
00044 class ConnectionKeeperPrivate
00045 {
00046 REFERENCE_OBJECT (ConnectionKeeperPrivate)
00047
00048 public:
00049 LocalPeer *localPeer;
00050 UdpHostCache *udpHostCache;
00051 SlotAllocator *slotAllocator;
00052 NodeCache *nodeCache;
00053 bool isBootstrapping;
00054 QTimer bootstrappingTimer;
00055 QDateTime bootstrappingStart;
00056
00057 NodeSet getBootstrapNodes (int count);
00058 NodeSet getConnectNodes (int count);
00059
00060 ConnectionKeeperPrivate (LocalPeer *localPeer_)
00061 : localPeer (localPeer_),
00062 udpHostCache (localPeer_->udpHostCache()),
00063 slotAllocator (localPeer->slotAllocator()),
00064 nodeCache (localPeer->nodeCache()),
00065 isBootstrapping (false),
00066 bootstrappingTimer(), bootstrappingStart()
00067 {}
00068
00069 };
00070
00071 }
00072 }
00073
00076 NodeSet ConnectionKeeperPrivate::getBootstrapNodes (int count)
00077 {
00078 NodeCache::NodeAvailability availability = NodeCache::UnknownAvailability;
00079 NodeSet nodes;
00080 if (count == 0)
00081 return nodes;
00082
00083 HighUptimeHost highUptimeHost (uint(HighUptimeThreshold *
00084 DailyUptime::MaximalUptime));
00085 nodes += nodeCache->getNodes (count - nodes.count(), availability, true,
00086 highUptimeHost);
00087 nodes += nodeCache->getNodes (count - nodes.count(), availability, true);
00088 nodes += nodeCache->getNodes (count - nodes.count(), availability, false,
00089 highUptimeHost);
00090 nodes += nodeCache->getNodes (count - nodes.count(), availability, false);
00091 return nodes;
00092 }
00093
00096 NodeSet ConnectionKeeperPrivate::getConnectNodes (int count)
00097 {
00098 NodeSet nodes;
00099 NodeCache::NodeAvailability availability = NodeCache::UnknownAvailability;
00100 if (count == 0)
00101 return nodes;
00102 if (localPeer->isUltrapeer())
00103 nodes += nodeCache->getNodes (count - nodes.count(), availability,
00104 true, HasUltrapeerSlots());
00105 else
00106 nodes += nodeCache->getNodes (count - nodes.count(), availability,
00107 true, HasLeafSlots());
00108 nodes += nodeCache->getNodes (count - nodes.count(), availability, true);
00109 return nodes;
00110 }
00111
00112 ConnectionKeeper::ConnectionKeeper (LocalPeer *localPeer)
00113 : p (new ConnectionKeeperPrivate (localPeer))
00114 {
00115 connect (&p->bootstrappingTimer, SIGNAL (timeout()),
00116 this, SLOT (bootstrap()));
00117 }
00118
00119 ConnectionKeeper::~ConnectionKeeper()
00120 {
00121 delete p;
00122 }
00123
00124 void ConnectionKeeper::bootstrap()
00125 {
00126 if (!p->slotAllocator->isBootstrapping()) {
00127 p->isBootstrapping = false;
00128 p->bootstrappingTimer.stop();
00129 return;
00130 }
00131
00132 if (p->isBootstrapping == false) {
00133 p->isBootstrapping = true;
00134 p->bootstrappingStart = QDateTime::currentDateTime();
00135 p->bootstrappingTimer.start (UdpPingTimeout);
00136
00137 keepConnection();
00138 }
00139
00140 QDateTime now = QDateTime::currentDateTime();
00141 if (now < p->bootstrappingStart.addMSecs (UdpPingTries * UdpPingTimeout)) {
00142 connect (p->nodeCache, SIGNAL (nodeAdded()),
00143 this, SLOT (keepConnection()),
00144 Qt::QueuedConnection);
00145 doUdpPinging();
00146 } else {
00147
00148
00149
00150
00151
00152
00153 keepConnection();
00154 doUhcQuery();
00155 }
00156
00157 }
00158
00159 void ConnectionKeeper::keepConnection()
00160 {
00161 int count = p->slotAllocator->freeHandshakingSlots();
00162 if (count <= 0) {
00163
00164
00165
00166 disconnect (p->nodeCache, SIGNAL (nodeAdded()),
00167 this, SLOT (keepConnection()));
00168 return;
00169 }
00170
00171
00172 if (p->localPeer->isUltrapeer() && p->slotAllocator->isWellConnected())
00173 return;
00174
00175 if (!p->localPeer->isUltrapeer() && !p->slotAllocator->hasFreeUltrapeerSlots())
00176 return;
00177
00178 NodeSet nodes;
00179 nodes += p->getConnectNodes (count - nodes.count());
00180 nodes += p->getBootstrapNodes (count - nodes.count());
00181
00182 foreach (NodeAddress nodeAddress, nodes) {
00183 p->localPeer->connectToPeer (nodeAddress.hostAddress().toString(),
00184 nodeAddress.hostPort());
00185 }
00186 if (nodes.count() == 0) {
00187
00188
00189
00190
00191
00192
00193
00194 doUhcQuery();
00195 return;
00196 }
00197 }
00198
00199 void ConnectionKeeper::doUdpPinging()
00200 {
00201 int count = UdpPingsPerTry;
00202
00203
00204 NodeSet nodes;
00205 nodes = p->getBootstrapNodes (count);
00206 qDebug() << "bootstrap nodes:" << nodes.count();
00207 foreach (NodeAddress nodeAddress, nodes) {
00208
00209
00210
00211 p->nodeCache->updateNode (nodeAddress, NodeCache::NodeBusy);
00212 p->udpHostCache->queryNode (nodeAddress);
00213 }
00214
00215 if (nodes.count() == 0) {
00216 doUhcQuery();
00217 return;
00218 }
00219 }
00220
00221 void ConnectionKeeper::doUhcQuery()
00222 {
00229 connect (p->nodeCache, SIGNAL (nodeAdded()),
00230 this, SLOT (keepConnection()),
00231 Qt::QueuedConnection);
00232 p->udpHostCache->queryCache();
00233 return;
00234 }