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())
97 QPointer<Server> server = unchallengedServers.takeFirst();
106 QUdpSocket *socket(
const Server *server)
108 return socketPool.acquire(server->
address(), server->
port());
114 class Refresher::MasterClientInfo
119 connect(&lastChallengeTimer, SIGNAL(timeout()),
120 parent, SLOT(attemptTimeoutMasters()));
121 lastChallengeTimer.setSingleShot(
true);
122 lastChallengeTimer.setInterval(MASTER_SERVER_TIMEOUT_DELAY);
125 void fireLastChallengeSentTimer()
127 lastChallengeTimer.start();
130 bool isLastChallengeTimerActive()
const
132 return lastChallengeTimer.isActive();
136 QTimer lastChallengeTimer;
141 Refresher *Refresher::staticInstance =
nullptr;
142 QMutex Refresher::instanceMutex;
144 Refresher::Refresher()
148 d->bKeepRunning =
true;
149 d->delayBetweenResends = 1000;
151 this->connect(&d->flushPendingDatagramsTimer, SIGNAL(timeout()), SLOT(readAllPendingDatagrams()));
152 this->connect(&d->socketPool, SIGNAL(readyRead()), SLOT(readAllPendingDatagrams()));
153 d->flushPendingDatagramsTimer.start(1000);
156 Refresher::~Refresher()
161 void Refresher::attemptTimeoutMasters()
163 QList<MasterClient *> masters = d->registeredMasters.keys();
166 MasterClientInfo *pMasterInfo = d->registeredMasters[master];
167 if (!pMasterInfo->isLastChallengeTimerActive())
169 master->timeoutRefresh();
174 void Refresher::concludeRefresh()
177 d->socketPool.releaseAll();
183 if (staticInstance ==
nullptr)
185 QMutexLocker locker(&instanceMutex);
186 if (staticInstance ==
nullptr)
191 return staticInstance;
194 bool Refresher::isInstantiated()
196 return staticInstance !=
nullptr;
199 void Refresher::deinstantiate()
201 QMutexLocker locker(&instanceMutex);
202 if (isInstantiated())
204 delete staticInstance;
205 staticInstance =
nullptr;
209 Server *Refresher::findRefreshingServer(
const QHostAddress &address,
212 for (
const ServerRefreshTime &refreshOp : d->refreshingServers)
214 if (refreshOp.server.isNull())
218 if (refreshOp.server->address().toIPv4Address() == address.toIPv4Address() && refreshOp.server->port() == port)
220 return refreshOp.server;
226 bool Refresher::isAnythingToRefresh()
const
228 return d->hasAnyServers() || !d->registeredMasters.isEmpty() || !d->unchallengedMasters.isEmpty();
231 void Refresher::masterFinishedRefreshing()
234 const QList<ServerPtr> &servers = pMaster->servers();
235 for (ServerPtr pServer : servers)
240 unregisterMaster(pMaster);
242 if (servers.size() == 0 && !isAnythingToRefresh())
247 emit finishedQueryingMaster(pMaster);
250 void Refresher::purgeNullServers()
252 d->refreshingServers.removeAll(ServerRefreshTime(
nullptr));
253 d->unchallengedServers.removeAll(
nullptr);
258 d->bKeepRunning =
false;
263 if (!d->registeredMasters.contains(pMaster))
265 auto pMasterInfo =
new MasterClientInfo(
this);
266 this->connect(pMaster, SIGNAL(listUpdated()), SLOT(masterFinishedRefreshing()));
268 d->registeredMasters.insert(pMaster, pMasterInfo);
269 d->unchallengedMasters.insert(pMaster);
272 if (d->registeredMasters.size() == 1)
276 d->bSleeping =
false;
279 QTimer::singleShot(20,
this, SLOT(sendMasterQueries()));
286 bool hadAnyServers = d->hasAnyServers();
288 if (!d->isServerRegistered(server))
291 if (!refreshChecker.shouldRefresh())
295 d->unchallengedServers.append(server);
302 if (!hadAnyServers && d->hasAnyServers())
306 d->bSleeping =
false;
309 QTimer::singleShot(20,
this, SLOT(sendServerQueries()));
315 void Refresher::readAllPendingDatagrams()
317 while (d->socketPool.hasPendingDatagrams() && d->bKeepRunning)
319 readPendingDatagram();
323 void Refresher::readPendingDatagram()
325 QHostAddress address;
327 QByteArray dataArray = d->socketPool.readNextDatagram(&address, &port);
329 if (tryReadDatagramByMasterClient(address, port, dataArray))
333 tryReadDatagramByServer(address, port, dataArray);
336 void Refresher::sendMasterQueries()
338 while (!d->unchallengedMasters.isEmpty())
340 MasterClient *pMaster = *d->unchallengedMasters.begin();
342 MasterClientInfo *pMasterInfo = d->registeredMasters[pMaster];
343 pMasterInfo->fireLastChallengeSentTimer();
346 pMaster->
sendRequest(d->socketPool.acquireMasterSocket());
347 d->unchallengedMasters.remove(pMaster);
351 void Refresher::sendServerQueries()
353 if (!d->bKeepRunning)
359 if (d->hasAnyServers())
361 startNewServerRefresh();
362 resendCurrentServerRefreshesIfTimeout();
366 QTimer::singleShot(qMax(1, gConfig.doomseeker.querySpeed().intervalBetweenServers),
367 this, SLOT(sendServerQueries()));
371 if (!isAnythingToRefresh())
380 d->delayBetweenResends = qMax(delay, 100);
383 bool Refresher::start()
385 return d->socketPool.acquireMasterSocket() !=
nullptr;
388 void Refresher::startNewServerRefresh()
392 QPointer<Server> server = d->popNextUnchallengedServer();
393 if (!server.isNull())
395 if (server->sendRefreshQuery(d->socket(server)))
397 d->refreshingServers.append(server);
402 void Refresher::resendCurrentServerRefreshesIfTimeout()
404 for (
int i = 0; i < d->refreshingServers.size(); ++i)
406 ServerRefreshTime &refreshOp = d->refreshingServers[i];
407 if (refreshOp.time.elapsed() > d->delayBetweenResends)
409 if (refreshOp.server->sendRefreshQuery(d->socket(refreshOp.server)))
411 refreshOp.time.start();
415 d->refreshingServers.removeOne(refreshOp);
424 bool Refresher::tryReadDatagramByMasterClient(QHostAddress &address,
425 unsigned short port, QByteArray &packet)
427 for (
MasterClient *pMaster : d->registeredMasters.keys())
429 if (!d->bKeepRunning)
435 MasterClient::Response response = pMaster->
readResponse(packet);
438 case MasterClient::RESPONSE_BANNED:
439 case MasterClient::RESPONSE_WAIT:
440 case MasterClient::RESPONSE_BAD:
441 case MasterClient::RESPONSE_OLD:
442 pMaster->notifyResponse(response);
443 unregisterMaster(pMaster);
445 case MasterClient::RESPONSE_REPLY:
446 pMaster->
sendRequest(d->socketPool.acquireMasterSocket());
456 bool Refresher::tryReadDatagramByServer(
const QHostAddress &address,
457 unsigned short port, QByteArray &packet)
459 if (!d->bKeepRunning)
463 Server *server = findRefreshingServer(address, port);
464 if (server !=
nullptr)
474 ServerRefreshTime refreshOp(server);
475 d->refreshingServers.removeAll(refreshOp);
476 d->refreshingServers.append(refreshOp);
480 [[gnu::fallthrough]];
482 d->refreshingServers.removeAll(ServerRefreshTime(server));
483 server->
refreshStops(static_cast<Server::Response>(response));
489 ServerRefreshTime refreshOp(server);
490 d->refreshingServers.removeAll(refreshOp);
491 d->refreshingServers.append(refreshOp);
501 pMaster->disconnect(
this);
502 Data::MasterHashtableIt it = d->registeredMasters.find(pMaster);
503 if (it != d->registeredMasters.end())
505 MasterClientInfo *pMasterInfo = it.value();
507 d->registeredMasters.erase(it);