23 #include "refresher.h"
25 #include "configuration/doomseekerconfig.h"
26 #include "configuration/queryspeed.h"
28 #include "plugins/pluginloader.h"
29 #include "refresher/canrefreshserver.h"
30 #include "refresher/udpsocketpool.h"
31 #include "serverapi/masterclient.h"
32 #include "serverapi/mastermanager.h"
33 #include "serverapi/server.h"
35 #include <QElapsedTimer>
39 #include <QMutexLocker>
40 #if QT_VERSION >= 0x060000
41 #include <QRandomGenerator>
48 class ServerRefreshTime
51 QWeakPointer<Server> server;
54 ServerRefreshTime(ServerPtr server)
56 this->server = server;
60 bool operator==(
const ServerRefreshTime &other)
const
62 return server == other.server;
69 typedef QHash<MasterClient *, MasterClientInfo *> MasterHashtable;
70 typedef QHash<MasterClient *, MasterClientInfo *>::iterator MasterHashtableIt;
75 int delayBetweenResends;
76 QTimer flushPendingDatagramsTimer;
77 MasterHashtable registeredMasters;
79 QList<QWeakPointer<Server> > unchallengedServers;
80 QList<ServerRefreshTime> refreshingServers;
82 QSet<MasterClient *> unchallengedMasters;
84 bool hasAnyServers()
const
86 return !unchallengedServers.isEmpty() || !refreshingServers.isEmpty();
89 bool isServerRegistered(
const ServerPtr &server)
const
91 return unchallengedServers.contains(server) ||
92 refreshingServers.contains(ServerRefreshTime(server));
95 ServerPtr popNextUnchallengedServer()
97 while (!unchallengedServers.isEmpty())
100 #if QT_VERSION >= 0x060000
101 #define qrand() QRandomGenerator::global()->generate()
106 quint32 index =
static_cast<quint32
>(qrand()) % unchallengedServers.size();
107 ServerPtr server = unchallengedServers.takeAt(index).toStrongRef();
108 if (!server.isNull())
116 QUdpSocket *socket(
const ServerPtr &server)
118 return socketPool.acquire(server->address(), server->port());
124 class Refresher::MasterClientInfo
129 connect(&lastChallengeTimer, SIGNAL(timeout()),
130 parent, SLOT(attemptTimeoutMasters()));
131 lastChallengeTimer.setSingleShot(
true);
132 lastChallengeTimer.setInterval(MASTER_SERVER_TIMEOUT_DELAY);
135 void fireLastChallengeSentTimer()
137 lastChallengeTimer.start();
140 bool isLastChallengeTimerActive()
const
142 return lastChallengeTimer.isActive();
146 QTimer lastChallengeTimer;
151 Refresher *Refresher::staticInstance =
nullptr;
152 QMutex Refresher::instanceMutex;
154 Refresher::Refresher()
158 d->bKeepRunning =
true;
159 d->delayBetweenResends = 1000;
161 this->connect(&d->flushPendingDatagramsTimer, SIGNAL(timeout()), SLOT(readAllPendingDatagrams()));
162 this->connect(&d->socketPool, SIGNAL(readyRead()), SLOT(readAllPendingDatagrams()));
163 d->flushPendingDatagramsTimer.start(1000);
166 Refresher::~Refresher()
171 void Refresher::attemptTimeoutMasters()
173 QList<MasterClient *> masters = d->registeredMasters.keys();
176 MasterClientInfo *pMasterInfo = d->registeredMasters[master];
177 if (!pMasterInfo->isLastChallengeTimerActive())
179 master->timeoutRefresh();
184 void Refresher::concludeRefresh()
187 d->socketPool.releaseAll();
193 if (staticInstance ==
nullptr)
195 QMutexLocker locker(&instanceMutex);
196 if (staticInstance ==
nullptr)
201 return staticInstance;
204 bool Refresher::isInstantiated()
206 return staticInstance !=
nullptr;
209 void Refresher::deinstantiate()
211 QMutexLocker locker(&instanceMutex);
212 if (isInstantiated())
214 delete staticInstance;
215 staticInstance =
nullptr;
219 ServerPtr Refresher::findRefreshingServer(
const QHostAddress &address,
222 for (
auto it = d->refreshingServers.begin(); it != d->refreshingServers.end();)
224 ServerPtr server = it->server.toStrongRef();
227 it = d->refreshingServers.erase(it);
230 if (server->address().toIPv4Address() == address.toIPv4Address() && server->port() == port)
239 bool Refresher::isAnythingToRefresh()
const
241 return d->hasAnyServers() || !d->registeredMasters.isEmpty() || !d->unchallengedMasters.isEmpty();
244 void Refresher::masterFinishedRefreshing()
247 unregisterMaster(pMaster);
249 QTimer::singleShot(0,
this, [
this]()
251 if (!isAnythingToRefresh())
257 emit finishedQueryingMaster(pMaster);
262 d->bKeepRunning =
false;
267 if (!d->registeredMasters.contains(pMaster))
269 auto pMasterInfo =
new MasterClientInfo(
this);
270 this->connect(pMaster, SIGNAL(listUpdated()), SLOT(masterFinishedRefreshing()));
272 d->registeredMasters.insert(pMaster, pMasterInfo);
273 d->unchallengedMasters.insert(pMaster);
276 if (d->registeredMasters.size() == 1)
280 d->bSleeping =
false;
283 QTimer::singleShot(20,
this, SLOT(sendMasterQueries()));
290 bool hadAnyServers = d->hasAnyServers();
291 if (!d->isServerRegistered(server))
294 if (!refreshChecker.shouldRefresh())
298 d->unchallengedServers.append(server);
299 if (!server->isCustom() && !server->isLan())
304 server->refreshStarts();
305 if (!hadAnyServers && d->hasAnyServers())
309 d->bSleeping =
false;
312 QTimer::singleShot(20,
this, SLOT(sendServerQueries()));
318 void Refresher::readAllPendingDatagrams()
320 while (d->socketPool.hasPendingDatagrams() && d->bKeepRunning)
322 readPendingDatagram();
326 void Refresher::readPendingDatagram()
328 QHostAddress address;
330 QByteArray dataArray = d->socketPool.readNextDatagram(&address, &port);
332 if (tryReadDatagramByMasterClient(address, port, dataArray))
336 tryReadDatagramByServer(address, port, dataArray);
339 void Refresher::sendMasterQueries()
341 while (!d->unchallengedMasters.isEmpty())
343 MasterClient *pMaster = *d->unchallengedMasters.begin();
345 MasterClientInfo *pMasterInfo = d->registeredMasters[pMaster];
346 pMasterInfo->fireLastChallengeSentTimer();
349 pMaster->
sendRequest(d->socketPool.acquireMasterSocket());
350 d->unchallengedMasters.remove(pMaster);
354 void Refresher::sendServerQueries()
356 if (!d->bKeepRunning)
361 if (d->hasAnyServers())
363 startNewServerRefresh();
364 resendCurrentServerRefreshesIfTimeout();
368 QTimer::singleShot(qMax(1, gConfig.doomseeker.querySpeed().intervalBetweenServers),
369 this, SLOT(sendServerQueries()));
373 if (!isAnythingToRefresh())
382 d->delayBetweenResends = qMax(delay, 100);
385 bool Refresher::start()
387 return d->socketPool.acquireMasterSocket() !=
nullptr;
390 void Refresher::startNewServerRefresh()
394 ServerPtr server = d->popNextUnchallengedServer();
395 if (!server.isNull())
397 if (server->sendRefreshQuery(d->socket(server)))
399 d->refreshingServers.append(server);
404 void Refresher::resendCurrentServerRefreshesIfTimeout()
406 for (
auto it = d->refreshingServers.begin(); it != d->refreshingServers.end();)
408 ServerRefreshTime &refreshOp = *it;
409 ServerPtr server = refreshOp.server.toStrongRef();
412 it = d->refreshingServers.erase(it);
416 if (refreshOp.time.elapsed() > d->delayBetweenResends)
418 if (server->sendRefreshQuery(d->socket(server)))
420 refreshOp.time.start();
424 it = d->refreshingServers.erase(it);
432 bool Refresher::tryReadDatagramByMasterClient(QHostAddress &address,
433 unsigned short port, QByteArray &packet)
435 for (
MasterClient *pMaster : d->registeredMasters.keys())
437 if (!d->bKeepRunning)
443 MasterClient::Response response = pMaster->
readResponse(packet);
446 case MasterClient::RESPONSE_BANNED:
447 case MasterClient::RESPONSE_WAIT:
448 case MasterClient::RESPONSE_BAD:
449 case MasterClient::RESPONSE_OLD:
450 pMaster->notifyResponse(response);
451 unregisterMaster(pMaster);
453 case MasterClient::RESPONSE_REPLY:
454 pMaster->
sendRequest(d->socketPool.acquireMasterSocket());
464 bool Refresher::tryReadDatagramByServer(
const QHostAddress &address,
465 unsigned short port, QByteArray &packet)
467 if (!d->bKeepRunning)
471 ServerPtr server = findRefreshingServer(address, port);
472 if (!server.isNull())
475 int response = server->readRefreshQueryResponse(packet);
479 if (server->sendRefreshQuery(d->socket(server)))
482 ServerRefreshTime refreshOp(server);
483 d->refreshingServers.removeAll(refreshOp);
484 d->refreshingServers.append(refreshOp);
488 [[gnu::fallthrough]];
490 d->refreshingServers.removeAll(ServerRefreshTime(server));
491 server->refreshStops(static_cast<Server::Response>(response));
497 ServerRefreshTime refreshOp(server);
498 d->refreshingServers.removeAll(refreshOp);
499 d->refreshingServers.append(refreshOp);
509 pMaster->disconnect(
this);
510 Data::MasterHashtableIt it = d->registeredMasters.find(pMaster);
511 if (it != d->registeredMasters.end())
513 MasterClientInfo *pMasterInfo = it.value();
515 d->registeredMasters.erase(it);