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" 38 #include <QMutexLocker> 45 class ServerRefreshTime
48 QPointer<Server> server;
51 ServerRefreshTime(QPointer<Server> server)
53 this->server = server;
57 bool operator==(
const ServerRefreshTime &other)
59 return server == other.server;
66 typedef QHash<MasterClient *, MasterClientInfo *> MasterHashtable;
67 typedef QHash<MasterClient *, MasterClientInfo *>::iterator MasterHashtableIt;
72 int delayBetweenResends;
73 QTimer flushPendingDatagramsTimer;
74 MasterHashtable registeredMasters;
76 QList<QPointer<Server> > unchallengedServers;
77 QList<ServerRefreshTime> refreshingServers;
79 QSet<MasterClient *> unchallengedMasters;
81 bool hasAnyServers()
const 83 return !unchallengedServers.isEmpty() || !refreshingServers.isEmpty();
86 bool isServerRegistered(
Server *server)
const 88 return unchallengedServers.contains(server) ||
89 refreshingServers.contains(ServerRefreshTime(server));
92 QPointer<Server> popNextUnchallengedServer()
94 while (!unchallengedServers.isEmpty())
96 QPointer<Server> server = unchallengedServers.takeFirst();
105 QUdpSocket *socket(
const Server *server)
107 return socketPool.acquire(server->
address(), server->
port());
113 class Refresher::MasterClientInfo
118 connect(&lastChallengeTimer, SIGNAL(timeout()),
119 parent, SLOT(attemptTimeoutMasters()));
120 lastChallengeTimer.setSingleShot(
true);
121 lastChallengeTimer.setInterval(MASTER_SERVER_TIMEOUT_DELAY);
124 void fireLastChallengeSentTimer()
126 lastChallengeTimer.start();
129 bool isLastChallengeTimerActive()
const 131 return lastChallengeTimer.isActive();
135 QTimer lastChallengeTimer;
140 Refresher *Refresher::staticInstance =
nullptr;
141 QMutex Refresher::instanceMutex;
143 Refresher::Refresher()
147 d->bKeepRunning =
true;
148 d->delayBetweenResends = 1000;
150 this->connect(&d->flushPendingDatagramsTimer, SIGNAL(timeout()), SLOT(readAllPendingDatagrams()));
151 this->connect(&d->socketPool, SIGNAL(readyRead()), SLOT(readAllPendingDatagrams()));
152 d->flushPendingDatagramsTimer.start(1000);
155 Refresher::~Refresher()
160 void Refresher::attemptTimeoutMasters()
162 QList<MasterClient *> masters = d->registeredMasters.keys();
165 MasterClientInfo *pMasterInfo = d->registeredMasters[master];
166 if (!pMasterInfo->isLastChallengeTimerActive())
168 master->timeoutRefresh();
173 void Refresher::concludeRefresh()
176 d->socketPool.releaseAll();
177 emit sleepingModeEnter();
182 if (staticInstance ==
nullptr)
184 QMutexLocker locker(&instanceMutex);
185 if (staticInstance ==
nullptr)
190 return staticInstance;
193 bool Refresher::isInstantiated()
195 return staticInstance !=
nullptr;
198 void Refresher::deinstantiate()
200 QMutexLocker locker(&instanceMutex);
201 if (isInstantiated())
203 delete staticInstance;
204 staticInstance =
nullptr;
208 Server *Refresher::findRefreshingServer(
const QHostAddress &address,
211 for (
const ServerRefreshTime &refreshOp : d->refreshingServers)
213 if (refreshOp.server.isNull())
217 if (refreshOp.server->address().toIPv4Address() == address.toIPv4Address() && refreshOp.server->port() == port)
219 return refreshOp.server;
225 bool Refresher::isAnythingToRefresh()
const 227 return d->hasAnyServers() || !d->registeredMasters.isEmpty() || !d->unchallengedMasters.isEmpty();
230 void Refresher::masterFinishedRefreshing()
233 const QList<ServerPtr> &servers = pMaster->servers();
234 for (ServerPtr pServer : servers)
236 registerServer(pServer.data());
239 unregisterMaster(pMaster);
241 if (servers.size() == 0 && !isAnythingToRefresh())
246 emit finishedQueryingMaster(pMaster);
249 void Refresher::purgeNullServers()
251 d->refreshingServers.removeAll(ServerRefreshTime(
nullptr));
252 d->unchallengedServers.removeAll(
nullptr);
257 d->bKeepRunning =
false;
262 if (!d->registeredMasters.contains(pMaster))
264 auto pMasterInfo =
new MasterClientInfo(
this);
265 this->connect(pMaster, SIGNAL(listUpdated()), SLOT(masterFinishedRefreshing()));
267 d->registeredMasters.insert(pMaster, pMasterInfo);
268 d->unchallengedMasters.insert(pMaster);
271 if (d->registeredMasters.size() == 1)
275 d->bSleeping =
false;
276 emit sleepingModeExit();
278 QTimer::singleShot(20,
this, SLOT(sendMasterQueries()));
285 bool hadAnyServers = d->hasAnyServers();
287 if (!d->isServerRegistered(server))
290 if (!refreshChecker.shouldRefresh())
294 d->unchallengedServers.append(server);
301 if (!hadAnyServers && d->hasAnyServers())
305 d->bSleeping =
false;
306 emit sleepingModeExit();
308 QTimer::singleShot(20,
this, SLOT(sendServerQueries()));
314 void Refresher::readAllPendingDatagrams()
316 while (d->socketPool.hasPendingDatagrams() && d->bKeepRunning)
318 readPendingDatagram();
322 void Refresher::readPendingDatagram()
324 QHostAddress address;
326 QByteArray dataArray = d->socketPool.readNextDatagram(&address, &port);
328 if (tryReadDatagramByMasterClient(address, port, dataArray))
332 tryReadDatagramByServer(address, port, dataArray);
335 void Refresher::sendMasterQueries()
337 while (!d->unchallengedMasters.isEmpty())
339 MasterClient *pMaster = *d->unchallengedMasters.begin();
341 MasterClientInfo *pMasterInfo = d->registeredMasters[pMaster];
342 pMasterInfo->fireLastChallengeSentTimer();
345 pMaster->
sendRequest(d->socketPool.acquireMasterSocket());
346 d->unchallengedMasters.remove(pMaster);
350 void Refresher::sendServerQueries()
352 if (!d->bKeepRunning)
358 if (d->hasAnyServers())
360 startNewServerRefresh();
361 resendCurrentServerRefreshesIfTimeout();
365 QTimer::singleShot(qMax(1, gConfig.doomseeker.querySpeed().intervalBetweenServers),
366 this, SLOT(sendServerQueries()));
370 if (!isAnythingToRefresh())
379 d->delayBetweenResends = qMax(delay, 100);
382 bool Refresher::start()
384 return d->socketPool.acquireMasterSocket() !=
nullptr;
387 void Refresher::startNewServerRefresh()
391 QPointer<Server> server = d->popNextUnchallengedServer();
392 if (!server.isNull())
394 if (server->sendRefreshQuery(d->socket(server)))
396 d->refreshingServers.append(server);
401 void Refresher::resendCurrentServerRefreshesIfTimeout()
403 for (
int i = 0; i < d->refreshingServers.size(); ++i)
405 ServerRefreshTime &refreshOp = d->refreshingServers[i];
406 if (refreshOp.time.elapsed() > d->delayBetweenResends)
408 if (refreshOp.server->sendRefreshQuery(d->socket(refreshOp.server)))
410 refreshOp.time.start();
414 d->refreshingServers.removeOne(refreshOp);
423 bool Refresher::tryReadDatagramByMasterClient(QHostAddress &address,
424 unsigned short port, QByteArray &packet)
426 for (
MasterClient *pMaster : d->registeredMasters.keys())
428 if (!d->bKeepRunning)
432 if (pMaster->isAddressSame(address, port))
434 MasterClient::Response response = pMaster->readResponse(packet);
437 case MasterClient::RESPONSE_BANNED:
438 case MasterClient::RESPONSE_WAIT:
439 case MasterClient::RESPONSE_BAD:
440 case MasterClient::RESPONSE_OLD:
441 pMaster->notifyResponse(response);
442 unregisterMaster(pMaster);
444 case MasterClient::RESPONSE_REPLY:
445 pMaster->sendRequest(d->socketPool.acquireMasterSocket());
455 bool Refresher::tryReadDatagramByServer(
const QHostAddress &address,
456 unsigned short port, QByteArray &packet)
458 if (!d->bKeepRunning)
462 Server *server = findRefreshingServer(address, port);
463 if (server !=
nullptr)
473 ServerRefreshTime refreshOp(server);
474 d->refreshingServers.removeAll(refreshOp);
475 d->refreshingServers.append(refreshOp);
479 [[gnu::fallthrough]];
481 d->refreshingServers.removeAll(ServerRefreshTime(server));
482 server->
refreshStops(static_cast<Server::Response>(response));
488 ServerRefreshTime refreshOp(server);
489 d->refreshingServers.removeAll(refreshOp);
490 d->refreshingServers.append(refreshOp);
500 pMaster->disconnect(
this);
501 Data::MasterHashtableIt it = d->registeredMasters.find(pMaster);
502 if (it != d->registeredMasters.end())
504 MasterClientInfo *pMasterInfo = it.value();
506 d->registeredMasters.erase(it);
Waiting for additional packets.
bool sendRequest(QUdpSocket *socket)
Sends request packet through socket.
void setDelayBetweenResends(int delay)
A representation of a server for a given game.
void registerMaster(MasterClient *pMaster)
Doomseeker needs to send some more challenge data to the server.
Response from the server was erroneous.
virtual void refreshStarts()
Response readRefreshQueryResponse(const QByteArray &data)
Entry point for Refresher that pushes response packet for parsing.
bool isLan() const
Does this server come from LAN.
void refreshStarts()
Called when server begins refreshing routine.
void refreshStops(Response response)
Called when server finishes refreshing routine.
bool registerServer(Server *server)
Abstract base for all MasterClients.
unsigned short port() const
Network port on which this server is hosted.
bool isCustom() const
Is this a custom server defined by the user?
const QHostAddress & address() const
Address of this server.
bool sendRefreshQuery(QUdpSocket *socket)
Method called by the refreshing thread; sends the challenge query through refresher's socket...