23 #include "refresher.h"
25 #include "configuration/queryspeed.h"
26 #include "refresher/canrefreshserver.h"
27 #include "serverapi/masterclient.h"
28 #include "serverapi/mastermanager.h"
29 #include "plugins/pluginloader.h"
30 #include "serverapi/server.h"
31 #include "configuration/doomseekerconfig.h"
36 #include <QMutexLocker>
44 class ServerRefreshTime
47 QPointer<Server> server;
50 ServerRefreshTime(QPointer<Server> server)
52 this->server = server;
56 bool operator==(
const ServerRefreshTime& other)
58 return server == other.server;
65 typedef QHash<MasterClient*, MasterClientInfo*> MasterHashtable;
66 typedef QHash<MasterClient*, MasterClientInfo*>::iterator MasterHashtableIt;
71 int delayBetweenResends;
72 MasterHashtable registeredMasters;
74 QList<QPointer<Server> > unchallengedServers;
75 QList<ServerRefreshTime> refreshingServers;
77 QSet<MasterClient*> unchallengedMasters;
79 bool hasAnyServers()
const
81 return !unchallengedServers.isEmpty() || !refreshingServers.isEmpty();
84 bool isServerRegistered(
Server *server)
const
86 return unchallengedServers.contains(server) ||
87 refreshingServers.contains(ServerRefreshTime(server));
90 QPointer<Server> popNextUnchallengedServer()
92 while (!unchallengedServers.isEmpty())
94 QPointer<Server> server = unchallengedServers.takeFirst();
106 class Refresher::MasterClientInfo
111 connect(&lastChallengeTimer, SIGNAL(timeout()),
112 parent, SLOT(attemptTimeoutMasters()));
113 lastChallengeTimer.setSingleShot(
true);
114 lastChallengeTimer.setInterval(MASTER_SERVER_TIMEOUT_DELAY);
117 void fireLastChallengeSentTimer()
119 lastChallengeTimer.start();
122 bool isLastChallengeTimerActive()
const
124 return lastChallengeTimer.isActive();
128 QTimer lastChallengeTimer;
133 Refresher* Refresher::staticInstance = NULL;
134 QMutex Refresher::instanceMutex;
136 Refresher::Refresher()
140 d->bKeepRunning =
true;
141 d->delayBetweenResends = 1000;
145 Refresher::~Refresher()
151 void Refresher::attemptTimeoutMasters()
153 QList<MasterClient*> masters = d->registeredMasters.keys();
156 MasterClientInfo* pMasterInfo = d->registeredMasters[master];
157 if (!pMasterInfo->isLastChallengeTimerActive())
166 if (staticInstance == NULL)
168 QMutexLocker locker(&instanceMutex);
169 if (staticInstance == NULL)
174 return staticInstance;
177 bool Refresher::isInstantiated()
179 return staticInstance != NULL;
182 void Refresher::deinstantiate()
184 QMutexLocker locker(&instanceMutex);
185 if (isInstantiated())
187 delete staticInstance;
188 staticInstance = NULL;
192 Server* Refresher::findRefreshingServer(
const QHostAddress& address,
195 foreach (
const ServerRefreshTime& refreshOp, d->refreshingServers)
197 if (refreshOp.server.isNull())
201 if (refreshOp.server->address() == address && refreshOp.server->port() == port)
203 return refreshOp.server;
209 bool Refresher::isAnythingToRefresh()
const
211 return d->hasAnyServers() || !d->registeredMasters.isEmpty() || !d->unchallengedMasters.isEmpty();
214 void Refresher::masterFinishedRefreshing()
217 const QList<ServerPtr>& servers = pMaster->servers();
218 foreach (ServerPtr pServer, servers)
223 unregisterMaster(pMaster);
225 if (servers.size() == 0 && !isAnythingToRefresh())
231 emit finishedQueryingMaster(pMaster);
234 void Refresher::purgeNullServers()
236 d->refreshingServers.removeAll(ServerRefreshTime(NULL));
237 d->unchallengedServers.removeAll(NULL);
242 d->bKeepRunning =
false;
247 if (!d->registeredMasters.contains(pMaster))
249 MasterClientInfo* pMasterInfo =
new MasterClientInfo(
this);
250 this->connect(pMaster, SIGNAL(listUpdated()), SLOT(masterFinishedRefreshing()));
252 d->registeredMasters.insert(pMaster, pMasterInfo);
253 d->unchallengedMasters.insert(pMaster);
256 if (d->registeredMasters.size() == 1)
260 d->bSleeping =
false;
263 QTimer::singleShot(20,
this, SLOT(sendMasterQueries()));
270 bool hadAnyServers = d->hasAnyServers();
272 if (!d->isServerRegistered(server))
275 if (!refreshChecker.shouldRefresh())
279 d->unchallengedServers.append(server);
286 if (!hadAnyServers && d->hasAnyServers())
290 d->bSleeping =
false;
293 QTimer::singleShot(20,
this, SLOT(sendServerQueries()));
299 void Refresher::readAllPendingDatagrams()
301 while(d->socket->hasPendingDatagrams() && d->bKeepRunning)
303 readPendingDatagram();
307 void Refresher::readPendingDatagram()
309 QHostAddress address;
311 qint64 size = d->socket->pendingDatagramSize();
312 char* data =
new char[size];
313 d->socket->readDatagram(data, size, &address, &port);
315 QByteArray dataArray(data, size);
318 if (tryReadDatagramByMasterClient(address, port, dataArray))
322 tryReadDatagramByServer(address, port, dataArray);
325 void Refresher::sendMasterQueries()
327 while(!d->unchallengedMasters.isEmpty())
329 MasterClient* pMaster = *d->unchallengedMasters.begin();
331 MasterClientInfo* pMasterInfo = d->registeredMasters[pMaster];
332 pMasterInfo->fireLastChallengeSentTimer();
336 d->unchallengedMasters.remove(pMaster);
340 void Refresher::sendServerQueries()
342 if (!d->bKeepRunning)
348 if (d->hasAnyServers())
350 startNewServerRefresh();
351 resendCurrentServerRefreshesIfTimeout();
355 QTimer::singleShot(qMax(1, gConfig.doomseeker.querySpeed().intervalBetweenServers),
356 this, SLOT(sendServerQueries()));
360 if (!isAnythingToRefresh())
370 d->delayBetweenResends = qMax(delay, 100);
373 bool Refresher::start()
375 QUdpSocket* socket =
new QUdpSocket();
376 this->connect(socket, SIGNAL(readyRead()),
377 SLOT(readAllPendingDatagrams()));
390 void Refresher::startNewServerRefresh()
394 QPointer<Server> server = d->popNextUnchallengedServer();
395 if (!server.isNull())
397 if(server->sendRefreshQuery(d->socket))
399 d->refreshingServers.append(server);
404 void Refresher::resendCurrentServerRefreshesIfTimeout()
406 for (
int i = 0; i < d->refreshingServers.size(); ++i)
408 ServerRefreshTime &refreshOp = d->refreshingServers[i];
409 if (refreshOp.time.elapsed() > d->delayBetweenResends)
411 if (refreshOp.server->sendRefreshQuery(d->socket))
413 refreshOp.time.start();
417 d->refreshingServers.removeOne(refreshOp);
426 bool Refresher::tryReadDatagramByMasterClient(QHostAddress& address,
427 unsigned short port, QByteArray& packet)
429 foreach (
MasterClient* pMaster, d->registeredMasters.keys())
431 if (!d->bKeepRunning)
437 MasterClient::Response response = pMaster->
readResponse(packet);
440 case MasterClient::RESPONSE_BANNED:
441 case MasterClient::RESPONSE_WAIT:
442 case MasterClient::RESPONSE_BAD:
443 case MasterClient::RESPONSE_OLD:
444 pMaster->notifyResponse(response);
445 unregisterMaster(pMaster);
447 case MasterClient::RESPONSE_REPLY:
458 bool Refresher::tryReadDatagramByServer(
const QHostAddress& address,
459 unsigned short port, QByteArray& packet)
461 if (!d->bKeepRunning)
465 Server* server = findRefreshingServer(address, port);
476 ServerRefreshTime refreshOp(server);
477 d->refreshingServers.removeAll(refreshOp);
478 d->refreshingServers.append(refreshOp);
484 d->refreshingServers.removeAll(ServerRefreshTime(server));
485 server->
refreshStops(static_cast<Server::Response>(response));
491 ServerRefreshTime refreshOp(server);
492 d->refreshingServers.removeAll(refreshOp);
493 d->refreshingServers.append(refreshOp);
503 Data::MasterHashtableIt it = d->registeredMasters.find(pMaster);
504 if (it != d->registeredMasters.end())
506 MasterClientInfo* pMasterInfo = it.value();
508 d->registeredMasters.erase(it);
Waiting for additional packets.
Response readResponse(const QByteArray &data)
Calls readMasterResponse and handles packet caching.
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 erroreneous.
virtual void refreshStarts()
Response readRefreshQueryResponse(const QByteArray &data)
Entry point for Refresher that pushes response packet for parsing.
void timeoutRefresh()
Times the refreshing process out.
void refreshStarts()
Called when server begins refreshing routine.
void refreshStops(Response response)
Called when server finishes refreshing routine.
bool isAddressSame(const QHostAddress &address, unsigned short port) const
Returns true if the passed address:port is the same as this master server's.
bool registerServer(Server *server)
Abstract base for all MasterClients.
bool isCustom() const
Is this a custom server defined by the user?
bool sendRefreshQuery(QUdpSocket *socket)
Method called by the refreshing thread; sends the challenge query through refresher's socket...