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>
46 class ServerRefreshTime
49 QPointer<Server> server;
52 ServerRefreshTime(QPointer<Server> server)
54 this->server = server;
58 bool operator==(
const ServerRefreshTime &other)
const
60 return server == other.server;
67 typedef QHash<MasterClient *, MasterClientInfo *> MasterHashtable;
68 typedef QHash<MasterClient *, MasterClientInfo *>::iterator MasterHashtableIt;
73 int delayBetweenResends;
74 QTimer flushPendingDatagramsTimer;
75 MasterHashtable registeredMasters;
77 QList<QPointer<Server> > unchallengedServers;
78 QList<ServerRefreshTime> refreshingServers;
80 QSet<MasterClient *> unchallengedMasters;
82 bool hasAnyServers()
const
84 return !unchallengedServers.isEmpty() || !refreshingServers.isEmpty();
87 bool isServerRegistered(
Server *server)
const
89 return unchallengedServers.contains(server) ||
90 refreshingServers.contains(ServerRefreshTime(server));
93 QPointer<Server> popNextUnchallengedServer()
95 while (!unchallengedServers.isEmpty())
99 quint32 index =
static_cast<quint32
>(qrand()) % unchallengedServers.size();
100 QPointer<Server> server = unchallengedServers.takeAt(index);
101 if (!server.isNull())
109 QUdpSocket *socket(
const Server *server)
111 return socketPool.acquire(server->
address(), server->
port());
117 class Refresher::MasterClientInfo
122 connect(&lastChallengeTimer, SIGNAL(timeout()),
123 parent, SLOT(attemptTimeoutMasters()));
124 lastChallengeTimer.setSingleShot(
true);
125 lastChallengeTimer.setInterval(MASTER_SERVER_TIMEOUT_DELAY);
128 void fireLastChallengeSentTimer()
130 lastChallengeTimer.start();
133 bool isLastChallengeTimerActive()
const
135 return lastChallengeTimer.isActive();
139 QTimer lastChallengeTimer;
144 Refresher *Refresher::staticInstance =
nullptr;
145 QMutex Refresher::instanceMutex;
147 Refresher::Refresher()
151 d->bKeepRunning =
true;
152 d->delayBetweenResends = 1000;
154 this->connect(&d->flushPendingDatagramsTimer, SIGNAL(timeout()), SLOT(readAllPendingDatagrams()));
155 this->connect(&d->socketPool, SIGNAL(readyRead()), SLOT(readAllPendingDatagrams()));
156 d->flushPendingDatagramsTimer.start(1000);
159 Refresher::~Refresher()
164 void Refresher::attemptTimeoutMasters()
166 QList<MasterClient *> masters = d->registeredMasters.keys();
169 MasterClientInfo *pMasterInfo = d->registeredMasters[master];
170 if (!pMasterInfo->isLastChallengeTimerActive())
172 master->timeoutRefresh();
177 void Refresher::concludeRefresh()
180 d->socketPool.releaseAll();
186 if (staticInstance ==
nullptr)
188 QMutexLocker locker(&instanceMutex);
189 if (staticInstance ==
nullptr)
194 return staticInstance;
197 bool Refresher::isInstantiated()
199 return staticInstance !=
nullptr;
202 void Refresher::deinstantiate()
204 QMutexLocker locker(&instanceMutex);
205 if (isInstantiated())
207 delete staticInstance;
208 staticInstance =
nullptr;
212 Server *Refresher::findRefreshingServer(
const QHostAddress &address,
215 for (
const ServerRefreshTime &refreshOp : d->refreshingServers)
217 if (refreshOp.server.isNull())
221 if (refreshOp.server->address().toIPv4Address() == address.toIPv4Address() && refreshOp.server->port() == port)
223 return refreshOp.server;
229 bool Refresher::isAnythingToRefresh()
const
231 return d->hasAnyServers() || !d->registeredMasters.isEmpty() || !d->unchallengedMasters.isEmpty();
234 void Refresher::masterFinishedRefreshing()
237 const QList<ServerPtr> &servers = pMaster->servers();
238 for (ServerPtr pServer : servers)
243 unregisterMaster(pMaster);
245 if (servers.size() == 0 && !isAnythingToRefresh())
250 emit finishedQueryingMaster(pMaster);
253 void Refresher::purgeNullServers()
255 d->refreshingServers.removeAll(ServerRefreshTime(
nullptr));
256 d->unchallengedServers.removeAll(
nullptr);
261 d->bKeepRunning =
false;
266 if (!d->registeredMasters.contains(pMaster))
268 auto pMasterInfo =
new MasterClientInfo(
this);
269 this->connect(pMaster, SIGNAL(listUpdated()), SLOT(masterFinishedRefreshing()));
271 d->registeredMasters.insert(pMaster, pMasterInfo);
272 d->unchallengedMasters.insert(pMaster);
275 if (d->registeredMasters.size() == 1)
279 d->bSleeping =
false;
282 QTimer::singleShot(20,
this, SLOT(sendMasterQueries()));
289 bool hadAnyServers = d->hasAnyServers();
291 if (!d->isServerRegistered(server))
294 if (!refreshChecker.shouldRefresh())
298 d->unchallengedServers.append(server);
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)
362 if (d->hasAnyServers())
364 startNewServerRefresh();
365 resendCurrentServerRefreshesIfTimeout();
369 QTimer::singleShot(qMax(1, gConfig.doomseeker.querySpeed().intervalBetweenServers),
370 this, SLOT(sendServerQueries()));
374 if (!isAnythingToRefresh())
383 d->delayBetweenResends = qMax(delay, 100);
386 bool Refresher::start()
388 return d->socketPool.acquireMasterSocket() !=
nullptr;
391 void Refresher::startNewServerRefresh()
395 QPointer<Server> server = d->popNextUnchallengedServer();
396 if (!server.isNull())
398 if (server->sendRefreshQuery(d->socket(server)))
400 d->refreshingServers.append(server);
405 void Refresher::resendCurrentServerRefreshesIfTimeout()
407 for (
int i = 0; i < d->refreshingServers.size(); ++i)
409 ServerRefreshTime &refreshOp = d->refreshingServers[i];
410 if (refreshOp.time.elapsed() > d->delayBetweenResends)
412 if (refreshOp.server->sendRefreshQuery(d->socket(refreshOp.server)))
414 refreshOp.time.start();
418 d->refreshingServers.removeOne(refreshOp);
427 bool Refresher::tryReadDatagramByMasterClient(QHostAddress &address,
428 unsigned short port, QByteArray &packet)
430 for (
MasterClient *pMaster : d->registeredMasters.keys())
432 if (!d->bKeepRunning)
438 MasterClient::Response response = pMaster->
readResponse(packet);
441 case MasterClient::RESPONSE_BANNED:
442 case MasterClient::RESPONSE_WAIT:
443 case MasterClient::RESPONSE_BAD:
444 case MasterClient::RESPONSE_OLD:
445 pMaster->notifyResponse(response);
446 unregisterMaster(pMaster);
448 case MasterClient::RESPONSE_REPLY:
449 pMaster->
sendRequest(d->socketPool.acquireMasterSocket());
459 bool Refresher::tryReadDatagramByServer(
const QHostAddress &address,
460 unsigned short port, QByteArray &packet)
462 if (!d->bKeepRunning)
466 Server *server = findRefreshingServer(address, port);
467 if (server !=
nullptr)
477 ServerRefreshTime refreshOp(server);
478 d->refreshingServers.removeAll(refreshOp);
479 d->refreshingServers.append(refreshOp);
483 [[gnu::fallthrough]];
485 d->refreshingServers.removeAll(ServerRefreshTime(server));
486 server->
refreshStops(static_cast<Server::Response>(response));
492 ServerRefreshTime refreshOp(server);
493 d->refreshingServers.removeAll(refreshOp);
494 d->refreshingServers.append(refreshOp);
504 pMaster->disconnect(
this);
505 Data::MasterHashtableIt it = d->registeredMasters.find(pMaster);
506 if (it != d->registeredMasters.end())
508 MasterClientInfo *pMasterInfo = it.value();
510 d->registeredMasters.erase(it);