Choker.cpp
Go to the documentation of this file.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 "Choker.h"
00025 #include "TransferSession.h"
00026 #include "Imports.cpp"
00027
00029
00033 Choker::Choker (Timer *timer,
00034 RandomNumberGenerator *randomNumberGenerator,
00035 TransferManagerState *transferManagerState)
00036 : timer (timer), randomNumberGenerator (randomNumberGenerator),
00037 transferManagerState (transferManagerState),
00038 sessions(), newSessions(), optimisticlyUnchokedSessions(),
00039 optimisticChokingCounter (0)
00040 {
00041 }
00042
00044 Choker::~Choker()
00045 {
00046 }
00047
00049 void Choker::start()
00050 {
00051
00052 timer->start (Callable <void()> (this, &Choker::chokingTime),
00053 ChokingTimeout);
00054 }
00055
00057 void Choker::stop()
00058 {
00059 timer->stop();
00060 }
00061
00063 void Choker::openedSession (TransferSession *session)
00064 {
00065 sessions += session;
00066 newSessions += session;
00067 }
00068
00070 void Choker::incomingPacket (TransferSession *, const Packet &)
00071 {
00072
00073 }
00074
00076 void Choker::outgoingPacket (TransferSession *, const Packet &)
00077 {
00078
00079 }
00080
00082
00087 void Choker::closedSession (TransferSession *session)
00088 {
00089 sessions.removeAll (session);
00090 newSessions.removeAll (session);
00091 }
00092
00094 void Choker::chokingTime()
00095 {
00096 doOptimisticUnchokingIfTimeHasCome();
00097 sortSessionsForSelection();
00098 reallocateUploadSlotsAndChokeUnchokeSessions();
00099 }
00100
00102
00110 void Choker::doOptimisticUnchokingIfTimeHasCome()
00111 {
00112 ++optimisticChokingCounter;
00113 if (optimisticChokingCounter == OptimisticChokingRate) {
00114 optimisticChokingCounter = 0;
00115 optimisticlyUnchokedSessions = choseOptimisticlyUnchokedSessions();
00116 foreach (TransferSession *session, optimisticlyUnchokedSessions) {
00117
00118
00119 Q_ASSERT (session->isPeerChoked());
00120 session->sendPacket (unchoke);
00121 }
00122 }
00123 }
00124
00126
00141 Choker::Sessions Choker::choseOptimisticlyUnchokedSessions()
00142 {
00143 Sessions chokedSessions;
00144 int numberOfSessionsSnubbed = 0;
00145 foreach (TransferSession *session, sessions) {
00146
00147 if (session->isPeerChoked() && !session->isPeerSeeder()) {
00148 chokedSessions += session;
00149
00150
00151 if (newSessions.contains (session)) {
00152 chokedSessions += session;
00153 chokedSessions += session;
00154 }
00155 }
00156
00157 if (session->areWeSnubbed() && transferManagerState->isDownloading())
00158 ++numberOfSessionsSnubbed;
00159 }
00160 newSessions.clear();
00161
00162
00163 Sessions optimisticUnchokes;
00164 for (int i = numberOfSessionsSnubbed + 1;
00165 i > 0 && !chokedSessions.isEmpty();
00166 --i) {
00167 int index = randomNumberGenerator->random() % chokedSessions.size();
00168 TransferSession *luckySession = chokedSessions.at (index);
00169 optimisticUnchokes += luckySession;
00170
00171 chokedSessions.removeAll (luckySession);
00172 }
00173 return optimisticUnchokes;
00174 }
00175
00177
00185 void Choker::sortSessionsForSelection()
00186 {
00187 if (transferManagerState->isDownloading())
00188 qStableSort (sessions.begin(), sessions.end(),
00189 moreDownloadedAndMoreInterested);
00190 else
00191 qStableSort (sessions.begin(), sessions.end(),
00192 moreUploadedAndMoreInterested);
00193 }
00194
00196
00207 void Choker::reallocateUploadSlotsAndChokeUnchokeSessions()
00208 {
00209 int uploadSlotsLeft = numberOfUploadSlots();
00210
00211 foreach (TransferSession *session, sessions) {
00212
00213 if (optimisticlyUnchokedSessions.contains (session))
00214 continue;
00215
00216 if (uploadSlotsLeft > 0 && !session->isPeerSeeder())
00217 unchokeSessionIfNeeded (session);
00218 else
00219 chokeSessionIfNeeded (session);
00220
00221
00222 if (session->isPeerInterested())
00223 --uploadSlotsLeft;
00224 }
00225 }
00226
00228
00232 int Choker::numberOfUploadSlots() const
00233 {
00234 int uploadSlots = UploadSlotsCount;
00235
00236 foreach (TransferSession *session, optimisticlyUnchokedSessions)
00237 if (session->isPeerInterested())
00238 --uploadSlots;
00239
00240 return uploadSlots;
00241 }
00242
00244 void Choker::chokeSessionIfNeeded (TransferSession *session)
00245 {
00246 if (!session->isPeerChoked())
00247 session->sendPacket (choke);
00248 }
00249
00251 void Choker::unchokeSessionIfNeeded (TransferSession *session)
00252 {
00253 if (session->isPeerChoked())
00254 session->sendPacket (unchoke);
00255 }
00256
00258
00267 bool Choker::moreDownloadedAndMoreInterested (const TransferSession *a,
00268 const TransferSession *b)
00269 {
00270 qint64 aSpeed = a->currentDownloadSpeed();
00271 qint64 bSpeed = b->currentDownloadSpeed();
00272
00273 if (aSpeed > bSpeed)
00274 return true;
00275 else if (aSpeed == bSpeed)
00276 return a->isPeerInterested() > b->isPeerInterested();
00277 else
00278 return false;
00279 }
00280
00282
00291 bool Choker::moreUploadedAndMoreInterested (const TransferSession *a,
00292 const TransferSession *b)
00293 {
00294 qint64 aSpeed = a->currentUploadSpeed();
00295 qint64 bSpeed = b->currentUploadSpeed();
00296
00297 if (aSpeed > bSpeed)
00298 return true;
00299 else if (aSpeed == bSpeed)
00300 return a->isPeerInterested() > b->isPeerInterested();
00301 else
00302 return false;
00303 }
00304
00305 const Choke Choker::choke;
00306 const Unchoke Choker::unchoke;