Browse Source

Fixed thread race condition.

It was introduced by the Open Pilot URL Factory code.
QGC4.4
dogmaphobic 10 years ago
parent
commit
8d95ffff50
  1. 103
      src/QtLocationPlugin/OpenPilotMaps.cc
  2. 27
      src/QtLocationPlugin/OpenPilotMaps.h
  3. 10
      src/QtLocationPlugin/qgeotilefetcherqgc.cpp
  4. 3
      src/QtLocationPlugin/qgeotilefetcherqgc.h

103
src/QtLocationPlugin/OpenPilotMaps.cc

@ -37,7 +37,7 @@ This file is part of the QGROUNDCONTROL project
namespace OpenPilot { namespace OpenPilot {
const QString ProviderStrings::levelsForSigPacSpainMap[] = const QString ProviderStrings::kLevelsForSigPacSpainMap[] =
{ "0", "1", "2", "3", "4", { "0", "1", "2", "3", "4",
"MTNSIGPAC", "MTNSIGPAC",
"MTN2000", "MTN2000", "MTN2000", "MTN2000", "MTN2000", "MTN2000", "MTN2000", "MTN2000", "MTN2000", "MTN2000",
@ -45,15 +45,13 @@ const QString ProviderStrings::levelsForSigPacSpainMap[] =
"MTN25", "MTN25", "MTN25", "MTN25",
"ORTOFOTOS", "ORTOFOTOS", "ORTOFOTOS", "ORTOFOTOS" }; "ORTOFOTOS", "ORTOFOTOS", "ORTOFOTOS", "ORTOFOTOS" };
const double UrlFactory::EarthRadiusKm = 6378.137; // WGS-84
ProviderStrings::ProviderStrings() ProviderStrings::ProviderStrings()
{ {
// Google version strings // Google version strings
VersionGoogleMap = "m@113"; VersionGoogleMap = "m@296306248";
VersionGoogleSatellite = "s"; VersionGoogleSatellite = "s@168";
VersionGoogleLabels = "h@221000000"; VersionGoogleLabels = "h@296000000";
VersionGoogleTerrain = "t@132,r@249000000"; VersionGoogleTerrain = "t@132,r@296000000";
SecGoogleWord = "Galileo"; SecGoogleWord = "Galileo";
// Google (China) version strings // Google (China) version strings
@ -91,18 +89,18 @@ ProviderStrings::ProviderStrings()
BingMapsClientToken = ""; BingMapsClientToken = "";
} }
UrlFactory::UrlFactory() UrlFactory::UrlFactory(QNetworkAccessManager *network)
: _isCorrectedGoogleVersions(false) : _timeout(5 * 1000)
, _correctGoogleVersions(true) , _googleVersionRetrieved(false)
, _timeout(5 * 1000) , _network(network)
, _googleReply(NULL)
{ {
Proxy.setType(QNetworkProxy::NoProxy);
UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7";
} }
UrlFactory::~UrlFactory() UrlFactory::~UrlFactory()
{ {
if(_googleReply)
_googleReply->deleteLater();
} }
QString UrlFactory::_tileXYToQuadKey(const int& tileX, const int& tileY, const int& levelOfDetail) const QString UrlFactory::_tileXYToQuadKey(const int& tileX, const int& tileY, const int& levelOfDetail) const
@ -128,38 +126,28 @@ int UrlFactory::_getServerNum(const QPoint &pos, const int &max) const
return (pos.x() + 2 * pos.y()) % max; return (pos.x() + 2 * pos.y()) % max;
} }
void UrlFactory::_tryCorrectGoogleVersions() void UrlFactory::_networkReplyError(QNetworkReply::NetworkError error)
{ {
static bool _kVersionRetrieved = false; qWarning() << "Could not connect to google maps. Error:" << error;
if (_kVersionRetrieved) { if(_googleReply)
return; {
} _googleReply->deleteLater();
QMutexLocker locker(&mutex); _googleReply = NULL;
if (_correctGoogleVersions && !_isCorrectedGoogleVersions) {
QNetworkReply* reply;
QNetworkRequest qheader;
QNetworkAccessManager network;
QEventLoop q;
QTimer tT;
tT.setSingleShot(true);
connect(&network, SIGNAL(finished(QNetworkReply *)), &q, SLOT(quit()));
connect(&tT, SIGNAL(timeout()), &q, SLOT(quit()));
network.setProxy(Proxy);
_isCorrectedGoogleVersions = true;
QString url = "https://maps.google.com/maps?output=classic";
qheader.setUrl(QUrl(url));
qheader.setRawHeader("User-Agent", UserAgent);
reply = network.get(qheader);
tT.start(_timeout);
q.exec();
if (!tT.isActive()) {
return;
} }
tT.stop(); }
if ((reply->error() != QNetworkReply::NoError)) {
void UrlFactory::_replyDestroyed()
{
_googleReply = NULL;
}
void UrlFactory::_googleVersionCompleted()
{
if (!_googleReply || (_googleReply->error() != QNetworkReply::NoError)) {
qDebug() << "Error collecting Google maps version info";
return; return;
} }
QString html = QString(reply->readAll()); QString html = QString(_googleReply->readAll());
QRegExp reg("\"*https://mts0.google.com/vt/lyrs=m@(\\d*)", Qt::CaseInsensitive); QRegExp reg("\"*https://mts0.google.com/vt/lyrs=m@(\\d*)", Qt::CaseInsensitive);
if (reg.indexIn(html) != -1) { if (reg.indexIn(html) != -1) {
QStringList gc = reg.capturedTexts(); QStringList gc = reg.capturedTexts();
@ -188,8 +176,33 @@ void UrlFactory::_tryCorrectGoogleVersions()
VersionGoogleTerrainChina = VersionGoogleTerrain; VersionGoogleTerrainChina = VersionGoogleTerrain;
VersionGoogleTerrainChina = VersionGoogleTerrain; VersionGoogleTerrainChina = VersionGoogleTerrain;
} }
reply->deleteLater(); _googleReply->deleteLater();
_kVersionRetrieved = true; _googleReply = NULL;
}
void UrlFactory::_tryCorrectGoogleVersions()
{
QMutexLocker locker(&_googleVersionMutex);
if (_googleVersionRetrieved) {
return;
}
_googleVersionRetrieved = true;
if(_network)
{
QNetworkRequest qheader;
QNetworkProxy proxy = _network->proxy();
QNetworkProxy tProxy;
tProxy.setType(QNetworkProxy::NoProxy);
_network->setProxy(tProxy);
QString url = "https://maps.google.com/maps?output=classic";
qheader.setUrl(QUrl(url));
QByteArray userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7";
qheader.setRawHeader("User-Agent", userAgent);
_googleReply = _network->get(qheader);
connect(_googleReply, SIGNAL(finished()), this, SLOT(_googleVersionCompleted()));
connect(_googleReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(_networkReplyError(QNetworkReply::NetworkError)));
connect(_googleReply, SIGNAL(destroyed()), this, SLOT(_replyDestroyed()));
_network->setProxy(proxy);
} }
} }
@ -459,7 +472,7 @@ QString UrlFactory::makeImageUrl(const MapType &type, const QPoint& pos, const i
break; break;
case SigPacSpainMap: case SigPacSpainMap:
{ {
return QString("http://sigpac.mapa.es/kmlserver/raster/%1@3785/%2.%3.%4.img").arg(levelsForSigPacSpainMap[zoom]).arg(zoom).arg(pos.x()).arg((2 << (zoom - 1)) - pos.y() - 1); return QString("http://sigpac.mapa.es/kmlserver/raster/%1@3785/%2.%3.%4.img").arg(kLevelsForSigPacSpainMap[zoom]).arg(zoom).arg(pos.x()).arg((2 << (zoom - 1)) - pos.y() - 1);
} }
break; break;
case YandexMapRu: case YandexMapRu:

27
src/QtLocationPlugin/OpenPilotMaps.h

@ -35,6 +35,7 @@ This file is part of the QGROUNDCONTROL project
#include <QPoint> #include <QPoint>
#include <QByteArray> #include <QByteArray>
#include <QNetworkProxy> #include <QNetworkProxy>
#include <QNetworkReply>
#include <QMutex> #include <QMutex>
namespace OpenPilot { namespace OpenPilot {
@ -88,10 +89,11 @@ enum MapType
YandexMapRu = 5000 YandexMapRu = 5000
}; };
class ProviderStrings { class ProviderStrings : public QObject {
Q_OBJECT
public: public:
ProviderStrings(); ProviderStrings();
static const QString levelsForSigPacSpainMap[]; static const QString kLevelsForSigPacSpainMap[];
QString GoogleMapsAPIKey; QString GoogleMapsAPIKey;
// Google version strings // Google version strings
QString VersionGoogleMap; QString VersionGoogleMap;
@ -127,29 +129,32 @@ public:
QString BingMapsClientToken; QString BingMapsClientToken;
}; };
class UrlFactory : public QObject, public ProviderStrings { class UrlFactory : public ProviderStrings {
Q_OBJECT Q_OBJECT
public: public:
QByteArray UserAgent;
QNetworkProxy Proxy;
UrlFactory(); UrlFactory(QNetworkAccessManager* network);
~UrlFactory(); ~UrlFactory();
QString makeImageUrl (const MapType &type, const QPoint &pos, const int &zoom, const QString &language); QString makeImageUrl (const MapType &type, const QPoint &pos, const int &zoom, const QString &language);
private slots:
void _networkReplyError (QNetworkReply::NetworkError error);
void _googleVersionCompleted ();
void _replyDestroyed ();
private: private:
void _getSecGoogleWords (const QPoint &pos, QString &sec1, QString &sec2); void _getSecGoogleWords (const QPoint &pos, QString &sec1, QString &sec2);
int _getServerNum (const QPoint& pos, const int &max) const; int _getServerNum (const QPoint& pos, const int &max) const;
void _tryCorrectGoogleVersions (); void _tryCorrectGoogleVersions ();
QString _tileXYToQuadKey (const int &tileX, const int &tileY, const int &levelOfDetail) const; QString _tileXYToQuadKey (const int &tileX, const int &tileY, const int &levelOfDetail) const;
bool _isCorrectedGoogleVersions;
bool _correctGoogleVersions;
int _timeout; int _timeout;
bool _googleVersionRetrieved;
QMutex mutex; QNetworkAccessManager* _network;
static const double EarthRadiusKm; QNetworkReply* _googleReply;
QMutex _googleVersionMutex;
QByteArray _userAgent;
}; };
} }

10
src/QtLocationPlugin/qgeotilefetcherqgc.cpp

@ -56,11 +56,19 @@ QGeoTileFetcherQGC::QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent)
: QGeoTileFetcher(parent) : QGeoTileFetcher(parent)
, m_networkManager(new QNetworkAccessManager(this)) , m_networkManager(new QNetworkAccessManager(this))
, m_userAgent("Qt Application") , m_userAgent("Qt Application")
, m_UrlFactory(NULL)
{ {
QStringList langs = QLocale::system().uiLanguages(); QStringList langs = QLocale::system().uiLanguages();
if (langs.length() > 0) { if (langs.length() > 0) {
m_Language = langs[0]; m_Language = langs[0];
} }
m_UrlFactory = new OpenPilot::UrlFactory(m_networkManager);
}
QGeoTileFetcherQGC::~QGeoTileFetcherQGC()
{
if(m_UrlFactory)
delete m_UrlFactory;
} }
void QGeoTileFetcherQGC::setUserAgent(const QByteArray &userAgent) void QGeoTileFetcherQGC::setUserAgent(const QByteArray &userAgent)
@ -71,7 +79,7 @@ void QGeoTileFetcherQGC::setUserAgent(const QByteArray &userAgent)
QGeoTiledMapReply *QGeoTileFetcherQGC::getTileImage(const QGeoTileSpec &spec) QGeoTiledMapReply *QGeoTileFetcherQGC::getTileImage(const QGeoTileSpec &spec)
{ {
QNetworkRequest request; QNetworkRequest request;
QString url = m_UrlFactory.makeImageUrl((OpenPilot::MapType)spec.mapId(), QPoint(spec.x(), spec.y()), spec.zoom(), m_Language); QString url = m_UrlFactory->makeImageUrl((OpenPilot::MapType)spec.mapId(), QPoint(spec.x(), spec.y()), spec.zoom(), m_Language);
request.setUrl(QUrl(url)); request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", m_userAgent); request.setRawHeader("User-Agent", m_userAgent);

3
src/QtLocationPlugin/qgeotilefetcherqgc.h

@ -60,6 +60,7 @@ class QGeoTileFetcherQGC : public QGeoTileFetcher
public: public:
explicit QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent = 0); explicit QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent = 0);
~QGeoTileFetcherQGC();
void setUserAgent(const QByteArray &userAgent); void setUserAgent(const QByteArray &userAgent);
@ -67,7 +68,7 @@ private:
QGeoTiledMapReply* getTileImage(const QGeoTileSpec &spec); QGeoTiledMapReply* getTileImage(const QGeoTileSpec &spec);
QNetworkAccessManager* m_networkManager; QNetworkAccessManager* m_networkManager;
QByteArray m_userAgent; QByteArray m_userAgent;
OpenPilot::UrlFactory m_UrlFactory; OpenPilot::UrlFactory* m_UrlFactory;
QString m_Language; QString m_Language;
}; };

Loading…
Cancel
Save