Compare commits

...
Author SHA1 Message Date
Automatic Release Builder d95b1c0441 new version: 2020.3.3 2020-11-12 11:14:23 +00:00
James Turner 837ba86d57 DNSClient: own requests, and cancel them on timeout
Fixes crashes where a request times-out, but then is completed by
UDN sometime afterwards, with a free-d object. Have the DNS::Client own
requests, and be able to retrieve the udns_query to cancel them, in 
the timeout case.

Fixes a couple of Sentry reports.
2020-11-12 09:39:58 +00:00
Automatic Release Builder 0cb1b463e1 Catalogs: fix ownership of new Catalogs
When doing the initial download of a Catalog, ensure we still keep
an owning ref to it.
2020-11-11 21:18:57 +00:00
Automatic Release Builder 8a772c8edd new version: 2020.3.2 2020-11-04 22:08:28 +00:00
James Turner 03bdad0a10 Try to capture cause of BTG load failures 2020-11-04 11:52:58 +00:00
James Turner 537776e1f8 TerraSync: fix local-file copying
Avoid downloading data corresponding to files shipped in FGData.
2020-11-04 11:22:48 +00:00
James Turner f34a4a304e Untar: log error details when output create fails
Trying to understand why writing to the output files fails for some
users.

Sentry-Id: FLIGHTGEAR-SS
2020-11-03 21:26:03 +00:00
8 changed files with 167 additions and 94 deletions
+1 -1
View File
@@ -1 +1 @@
2020.3.1 2020.3.3
+85 -47
View File
@@ -61,6 +61,10 @@ public:
struct dns_ctx * ctx; struct dns_ctx * ctx;
static size_t instanceCounter; static size_t instanceCounter;
using RequestVec = std::vector<Request_ptr>;
RequestVec _activeRequests;
}; };
size_t Client::ClientPrivate::instanceCounter = 0; size_t Client::ClientPrivate::instanceCounter = 0;
@@ -78,6 +82,11 @@ Request::~Request()
{ {
} }
void Request::cancel()
{
_cancelled = true;
}
bool Request::isTimeout() const bool Request::isTimeout() const
{ {
return (time(NULL) - _start) > _timeout_secs; return (time(NULL) - _start) > _timeout_secs;
@@ -114,18 +123,20 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
{ {
SRVRequest * r = static_cast<SRVRequest*>(data); SRVRequest * r = static_cast<SRVRequest*>(data);
if (result) { if (result) {
r->cname = result->dnssrv_cname; if (!r->isCancelled()) {
r->qname = result->dnssrv_qname; r->cname = result->dnssrv_cname;
r->ttl = result->dnssrv_ttl; r->qname = result->dnssrv_qname;
for (int i = 0; i < result->dnssrv_nrr; i++) { r->ttl = result->dnssrv_ttl;
SRVRequest::SRV_ptr srv(new SRVRequest::SRV); for (int i = 0; i < result->dnssrv_nrr; i++) {
r->entries.push_back(srv); SRVRequest::SRV_ptr srv(new SRVRequest::SRV);
srv->priority = result->dnssrv_srv[i].priority; r->entries.push_back(srv);
srv->weight = result->dnssrv_srv[i].weight; srv->priority = result->dnssrv_srv[i].priority;
srv->port = result->dnssrv_srv[i].port; srv->weight = result->dnssrv_srv[i].weight;
srv->target = result->dnssrv_srv[i].name; srv->port = result->dnssrv_srv[i].port;
srv->target = result->dnssrv_srv[i].name;
}
std::sort(r->entries.begin(), r->entries.end(), sortSRV);
} }
std::sort( r->entries.begin(), r->entries.end(), sortSRV );
free(result); free(result);
} }
r->setComplete(); r->setComplete();
@@ -134,11 +145,16 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
void SRVRequest::submit( Client * client ) void SRVRequest::submit( Client * client )
{ {
// if service is defined, pass service and protocol // if service is defined, pass service and protocol
if (!dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(), _service.empty() ? NULL : _protocol.c_str(), 0, dnscbSRV, this )) { auto q = dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(),
_service.empty() ? NULL : _protocol.c_str(),
0, dnscbSRV, this);
if (!q) {
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn()); SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
return; return;
} }
_start = time(NULL); _start = time(NULL);
_query = q;
} }
TXTRequest::TXTRequest( const std::string & dn ) : TXTRequest::TXTRequest( const std::string & dn ) :
@@ -151,22 +167,24 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
{ {
TXTRequest * r = static_cast<TXTRequest*>(data); TXTRequest * r = static_cast<TXTRequest*>(data);
if (result) { if (result) {
r->cname = result->dnstxt_cname; if (!r->isCancelled()) {
r->qname = result->dnstxt_qname; r->cname = result->dnstxt_cname;
r->ttl = result->dnstxt_ttl; r->qname = result->dnstxt_qname;
for (int i = 0; i < result->dnstxt_nrr; i++) { r->ttl = result->dnstxt_ttl;
//TODO: interprete the .len field of dnstxt_txt? for (int i = 0; i < result->dnstxt_nrr; i++) {
auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt); //TODO: interprete the .len field of dnstxt_txt?
if (!rawTxt) { auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt);
continue; if (!rawTxt) {
} continue;
}
const string txt{rawTxt}; const string txt{rawTxt};
r->entries.push_back(txt); r->entries.push_back(txt);
string_list tokens = simgear::strutils::split( txt, "=", 1 ); string_list tokens = simgear::strutils::split(txt, "=", 1);
if( tokens.size() == 2 ) { if (tokens.size() == 2) {
r->attributes[tokens[0]] = tokens[1]; r->attributes[tokens[0]] = tokens[1];
} }
}
} }
free(result); free(result);
} }
@@ -176,11 +194,13 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
void TXTRequest::submit( Client * client ) void TXTRequest::submit( Client * client )
{ {
// protocol and service an already encoded in DN so pass in NULL for both // protocol and service an already encoded in DN so pass in NULL for both
if (!dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this )) { auto q = dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this);
if (!q) {
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn()); SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
return; return;
} }
_start = time(NULL); _start = time(NULL);
_query = q;
} }
@@ -195,27 +215,29 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
{ {
NAPTRRequest * r = static_cast<NAPTRRequest*>(data); NAPTRRequest * r = static_cast<NAPTRRequest*>(data);
if (result) { if (result) {
r->cname = result->dnsnaptr_cname; if (!r->isCancelled()) {
r->qname = result->dnsnaptr_qname; r->cname = result->dnsnaptr_cname;
r->ttl = result->dnsnaptr_ttl; r->qname = result->dnsnaptr_qname;
for (int i = 0; i < result->dnsnaptr_nrr; i++) { r->ttl = result->dnsnaptr_ttl;
if( !r->qservice.empty() && r->qservice != result->dnsnaptr_naptr[i].service ) for (int i = 0; i < result->dnsnaptr_nrr; i++) {
continue; if (!r->qservice.empty() && r->qservice != result->dnsnaptr_naptr[i].service)
continue;
//TODO: case ignore and result flags may have more than one flag //TODO: case ignore and result flags may have more than one flag
if( !r->qflags.empty() && r->qflags != result->dnsnaptr_naptr[i].flags ) if (!r->qflags.empty() && r->qflags != result->dnsnaptr_naptr[i].flags)
continue; continue;
NAPTRRequest::NAPTR_ptr naptr(new NAPTRRequest::NAPTR); NAPTRRequest::NAPTR_ptr naptr(new NAPTRRequest::NAPTR);
r->entries.push_back(naptr); r->entries.push_back(naptr);
naptr->order = result->dnsnaptr_naptr[i].order; naptr->order = result->dnsnaptr_naptr[i].order;
naptr->preference = result->dnsnaptr_naptr[i].preference; naptr->preference = result->dnsnaptr_naptr[i].preference;
naptr->flags = result->dnsnaptr_naptr[i].flags; naptr->flags = result->dnsnaptr_naptr[i].flags;
naptr->service = result->dnsnaptr_naptr[i].service; naptr->service = result->dnsnaptr_naptr[i].service;
naptr->regexp = result->dnsnaptr_naptr[i].regexp; naptr->regexp = result->dnsnaptr_naptr[i].regexp;
naptr->replacement = result->dnsnaptr_naptr[i].replacement; naptr->replacement = result->dnsnaptr_naptr[i].replacement;
}
std::sort(r->entries.begin(), r->entries.end(), sortNAPTR);
} }
std::sort( r->entries.begin(), r->entries.end(), sortNAPTR );
free(result); free(result);
} }
r->setComplete(); r->setComplete();
@@ -223,11 +245,13 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
void NAPTRRequest::submit( Client * client ) void NAPTRRequest::submit( Client * client )
{ {
if (!dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this )) { auto q = dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this);
if (!q) {
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn()); SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
return; return;
} }
_start = time(NULL); _start = time(NULL);
_query = q;
} }
@@ -242,6 +266,7 @@ Client::Client() :
void Client::makeRequest(const Request_ptr& r) void Client::makeRequest(const Request_ptr& r)
{ {
d->_activeRequests.push_back(r);
r->submit(this); r->submit(this);
} }
@@ -252,6 +277,19 @@ void Client::update(int waitTimeout)
return; return;
dns_ioevent(d->ctx, now); dns_ioevent(d->ctx, now);
// drop our owning ref to completed requests,
// and cancel any which timed out
auto it = std::remove_if(d->_activeRequests.begin(), d->_activeRequests.end(),
[this](const Request_ptr& r) {
if (r->isTimeout()) {
dns_cancel(d->ctx, reinterpret_cast<struct dns_query*>(r->_query));
return true;
}
return r->isComplete();
});
d->_activeRequests.erase(it, d->_activeRequests.end());
} }
} // of namespace DNS } // of namespace DNS
+14 -4
View File
@@ -40,28 +40,38 @@ namespace DNS
{ {
class Client; class Client;
using UDNSQueryPtr = void*;
class Request : public SGReferenced class Request : public SGReferenced
{ {
public: public:
Request( const std::string & dn ); Request( const std::string & dn );
virtual ~Request(); virtual ~Request();
std::string getDn() const { return _dn; } const std::string& getDn() const { return _dn; }
int getType() const { return _type; } int getType() const { return _type; }
bool isComplete() const { return _complete; } bool isComplete() const { return _complete; }
bool isTimeout() const; bool isTimeout() const;
void setComplete( bool b = true ) { _complete = b; } void setComplete( bool b = true ) { _complete = b; }
bool isCancelled() const { return _cancelled; }
virtual void submit( Client * client) = 0; virtual void submit( Client * client) = 0;
void cancel();
std::string cname; std::string cname;
std::string qname; std::string qname;
unsigned ttl; unsigned ttl;
protected: protected:
friend class Client;
UDNSQueryPtr _query = nullptr;
std::string _dn; std::string _dn;
int _type; int _type;
bool _complete; bool _complete;
time_t _timeout_secs; time_t _timeout_secs;
time_t _start; time_t _start;
bool _cancelled = false;
}; };
typedef SGSharedPtr<Request> Request_ptr; typedef SGSharedPtr<Request> Request_ptr;
@@ -69,7 +79,7 @@ class NAPTRRequest : public Request
{ {
public: public:
NAPTRRequest( const std::string & dn ); NAPTRRequest( const std::string & dn );
virtual void submit( Client * client ); void submit(Client* client) override;
struct NAPTR : SGReferenced { struct NAPTR : SGReferenced {
int order; int order;
@@ -92,7 +102,7 @@ class SRVRequest : public Request
public: public:
SRVRequest( const std::string & dn ); SRVRequest( const std::string & dn );
SRVRequest( const std::string & dn, const string & service, const string & protocol ); SRVRequest( const std::string & dn, const string & service, const string & protocol );
virtual void submit( Client * client ); void submit(Client* client) override;
struct SRV : SGReferenced { struct SRV : SGReferenced {
int priority; int priority;
@@ -112,7 +122,7 @@ class TXTRequest : public Request
{ {
public: public:
TXTRequest( const std::string & dn ); TXTRequest( const std::string & dn );
virtual void submit( Client * client ); void submit(Client* client) override;
typedef std::vector<string> TXT_list; typedef std::vector<string> TXT_list;
typedef std::map<std::string,std::string> TXT_Attribute_map; typedef std::map<std::string,std::string> TXT_Attribute_map;
+35 -29
View File
@@ -221,42 +221,48 @@ public:
char* buf = nullptr; char* buf = nullptr;
size_t bufSize = 0; size_t bufSize = 0;
for (const auto& child : children) { for (auto &child : children) {
if (child.type != HTTPRepository::FileType) if (child.type != HTTPRepository::FileType)
continue; continue;
if (child.path.exists()) if (child.path.exists())
continue; continue;
SGPath cp = _repository->installedCopyPath; SGPath cp = _repository->installedCopyPath;
cp.append(relativePath()); cp.append(relativePath());
cp.append(child.name); cp.append(child.name);
if (!cp.exists()) { if (!cp.exists()) {
continue; continue;
} }
SGBinaryFile src(cp); SGBinaryFile src(cp);
SGBinaryFile dst(child.path); SGBinaryFile dst(child.path);
src.open(SG_IO_IN); src.open(SG_IO_IN);
dst.open(SG_IO_OUT); dst.open(SG_IO_OUT);
if (bufSize < cp.sizeInBytes()) { if (bufSize < cp.sizeInBytes()) {
bufSize = cp.sizeInBytes(); bufSize = cp.sizeInBytes();
free(buf); free(buf);
buf = (char*) malloc(bufSize); buf = (char *)malloc(bufSize);
if (!buf) { if (!buf) {
continue; continue;
} }
} }
src.read(buf, cp.sizeInBytes()); src.read(buf, cp.sizeInBytes());
dst.write(buf, cp.sizeInBytes()); dst.write(buf, cp.sizeInBytes());
src.close(); src.close();
dst.close(); dst.close();
} // reset caching
child.path.set_cached(false);
child.path.set_cached(true);
free(buf); std::string hash = computeHashForPath(child.path);
updatedFileContents(child.path, hash);
}
free(buf);
} }
void updateChildrenBasedOnHash() void updateChildrenBasedOnHash()
+7
View File
@@ -42,6 +42,7 @@
#include <simgear/bucket/newbucket.hxx> #include <simgear/bucket/newbucket.hxx>
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/math/SGGeometry.hxx> #include <simgear/math/SGGeometry.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
@@ -563,6 +564,12 @@ bool SGBinObject::read_bin( const SGPath& file ) {
// read headers // read headers
unsigned int header; unsigned int header;
sgReadUInt( fp, &header ); sgReadUInt( fp, &header );
if (sgReadError()) {
gzclose(fp);
throw sg_io_exception("Unable to read BTG header: " + simgear::strutils::error_string(errno), sg_location(file));
}
if ( ((header & 0xFF000000) >> 24) == 'S' && if ( ((header & 0xFF000000) >> 24) == 'S' &&
((header & 0x00FF0000) >> 16) == 'G' ) { ((header & 0x00FF0000) >> 16) == 'G' ) {
+3 -1
View File
@@ -31,6 +31,8 @@
#include <simgear/sg_inlines.h> #include <simgear/sg_inlines.h>
#include <simgear/io/sg_file.hxx> #include <simgear/io/sg_file.hxx>
#include <simgear/misc/sg_dir.hxx> #include <simgear/misc/sg_dir.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/io/iostreams/sgstream.hxx> #include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/package/unzip.h> #include <simgear/package/unzip.h>
@@ -592,7 +594,7 @@ public:
outFile.open(path, std::ios::binary | std::ios::trunc | std::ios::out); outFile.open(path, std::ios::binary | std::ios::trunc | std::ios::out);
if (outFile.fail()) { if (outFile.fail()) {
throw sg_io_exception("failed to open output file for writing", path); throw sg_io_exception("failed to open output file for writing:" + strutils::error_string(errno), path);
} }
while (!eof) { while (!eof) {
+11 -6
View File
@@ -722,12 +722,6 @@ void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
auto catIt = d->catalogs.find(aCat->id()); auto catIt = d->catalogs.find(aCat->id());
d->fireRefreshStatus(aCat, aReason); d->fireRefreshStatus(aCat, aReason);
if (aReason == Delegate::STATUS_IN_PROGRESS) {
d->refreshing.insert(aCat);
} else {
d->refreshing.erase(aCat);
}
if (aCat->isUserEnabled() && if (aCat->isUserEnabled() &&
(aReason == Delegate::STATUS_REFRESHED) && (aReason == Delegate::STATUS_REFRESHED) &&
(catIt == d->catalogs.end())) (catIt == d->catalogs.end()))
@@ -761,6 +755,17 @@ void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
} }
} // of catalog is disabled } // of catalog is disabled
// remove from refreshing /after/ checking for enable / disabled, since for
// new catalogs, the reference in d->refreshing might be our /only/
// reference to the catalog. Once the refresh is done (either failed or
// succeeded) the Catalog will be in either d->catalogs or
// d->disabledCatalogs
if (aReason == Delegate::STATUS_IN_PROGRESS) {
d->refreshing.insert(aCat);
} else {
d->refreshing.erase(aCat);
}
if (d->refreshing.empty()) { if (d->refreshing.empty()) {
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED); d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
d->firePackagesChanged(); d->firePackagesChanged();
+11 -6
View File
@@ -603,12 +603,6 @@ void SGTerraSync::WorkerThread::updateSyncSlot(SyncSlot &slot)
beginNormalSync(slot); beginNormalSync(slot);
} }
if (_installRoot.exists()) {
SGPath p = _installRoot;
p.append(slot.currentItem._dir);
slot.repository->setInstalledCopyPath(p);
}
try { try {
slot.repository->update(); slot.repository->update();
} catch (sg_exception& e) { } catch (sg_exception& e) {
@@ -676,6 +670,11 @@ void SGTerraSync::WorkerThread::beginSyncTile(SyncSlot& slot)
slot.repository.reset(new HTTPRepository(path, &_http)); slot.repository.reset(new HTTPRepository(path, &_http));
slot.repository->setBaseUrl(_httpServer + "/" + tileCategory); slot.repository->setBaseUrl(_httpServer + "/" + tileCategory);
if (_installRoot.exists()) {
SGPath p = _installRoot / tileCategory;
slot.repository->setInstalledCopyPath(p);
}
const auto dirPrefix = tenByTenDir + "/" + oneByOneDir; const auto dirPrefix = tenByTenDir + "/" + oneByOneDir;
// filter callback to *only* sync the 1x1 dir we want, if it exists // filter callback to *only* sync the 1x1 dir we want, if it exists
@@ -706,6 +705,12 @@ void SGTerraSync::WorkerThread::beginNormalSync(SyncSlot& slot)
path.append(slot.currentItem._dir); path.append(slot.currentItem._dir);
slot.repository.reset(new HTTPRepository(path, &_http)); slot.repository.reset(new HTTPRepository(path, &_http));
slot.repository->setBaseUrl(_httpServer + "/" + slot.currentItem._dir); slot.repository->setBaseUrl(_httpServer + "/" + slot.currentItem._dir);
if (_installRoot.exists()) {
SGPath p = _installRoot;
p.append(slot.currentItem._dir);
slot.repository->setInstalledCopyPath(p);
}
} }
void SGTerraSync::WorkerThread::runInternal() void SGTerraSync::WorkerThread::runInternal()